在 Raku 中进行单元测试时如何模拟类方法

Jul*_*lio 8 methods unit-testing mocking raku

假设我有一个这样的类:

class MyClass {
    method data-is-valid {
        return self!get-data ~~ m{^From};
    }

    method !get-data {
        return 'From Internet';
    }
}
Run Code Online (Sandbox Code Playgroud)

where!get-data方法从 Internet 获取一些数据。

是否可以模拟该方法,使其返回我自己的硬编码数据,以便我可以在不连接到 Internet 的情况下测试模块?

理想情况下,解决方案不应以任何方式修改类的定义。

注意:关于模块的单元测试子程序存在类似的问题

Jon*_*ton 9

我会首先重构以将获取逻辑拉出到不同的对象,并MyClass依赖于它:

class Downloader {
    method get-data {
        return 'From Internet';
    }
}

class MyClass {
    has Downloader $.downloader .= new;

    method data-is-valid {
        return $!downloader.get-data ~~ m{^From};
    }
}
Run Code Online (Sandbox Code Playgroud)

这是依赖倒置的一个例子,它是一种使代码可测试的有用技术(并且倾向于使其更容易以其他方式发展)。

通过此更改,现在可以使用Test::Mock模块来模拟Downloader

use Test;
use Test::Mock;

subtest 'Is valid when contains From' => {
    my $downloader = mocked Downloader, returning => {
        get-data => 'From: blah'
    };
    my $test = MyClass.new(:$downloader);
    ok $test.data-is-valid;
    check-mock $downloader,
        *.called('get-data', :1times);
}

subtest 'Is not valid when response does not contain From' => {
    my $downloader = mocked Downloader, returning => {
        get-data => 'To: blah'
    };
    my $test = MyClass.new(:$downloader);
    nok $test.data-is-valid;
    check-mock $downloader,
        *.called('get-data', :1times);
}
Run Code Online (Sandbox Code Playgroud)


Eli*_*sen 6

您可能想看看Test::Mock。从它的概要:

use Test;
use Test::Mock;

plan 2;

class Foo {
    method lol() { 'rofl' }
    method wtf() { 'oh ffs' }
}

my $x = mocked(Foo);

$x.lol();
$x.lol();

check-mock($x,
    *.called('lol', times => 2),
    *.never-called('wtf'),
);
Run Code Online (Sandbox Code Playgroud)