Unit testing 如何模拟完整模块?
我想测试一个模块Unit testing 如何模拟完整模块?,unit-testing,perl,mocking,Unit Testing,Perl,Mocking,我想测试一个模块B。此模块依赖于我不想测试的模块A。下面是我的软件包B的一个示例: use strict; use warnings FATAL => 'all'; use A; package B; sub to_test { return A::a(); } 在我的单元测试中,我想调用B::to_test,但我想手动指定A::A()必须返回的值。为此,我编写了一个模块mock.pm,其中包含aTo mock的所有子模块: use strict; use warn
B
。此模块依赖于我不想测试的模块A
。下面是我的软件包B
的一个示例:
use strict;
use warnings FATAL => 'all';
use A;
package B;
sub to_test {
return A::a();
}
在我的单元测试中,我想调用B::to_test
,但我想手动指定A::A()
必须返回的值。为此,我编写了一个模块mock.pm
,其中包含a
To mock的所有子模块:
use strict;
use warnings 'FATAL' => 'all';
package Mock::A;
sub a {
return "From mock";
}
1;
我知道我可以使用轻松地模拟A::A
,问题是包A
可能包含很多子组件,并且Test::MockModule
允许我逐个模拟它们
如何使用
moka
模拟完整的A
包?可以通过moka
中的sub重新定义包A
中定义的sub。为此,有三个条件:
必须定义与MockA
相同的包李>A
必须包含在MockA
的所有包含内容之后李>A
- 警告<代码>重新定义不能是致命的
MockA.pm
可以是以下文件:
use strict;
# No fatal error if a sub is redefined
use warnings 'FATAL' => 'all', 'NONFATAL' => 'redefine';
# Override package A
package A;
sub a {
return "From mock";
}
1;
在单元测试中:
use B; # B includes A
use MockA; # MockA overrides A
B::to_test() # B calls MockA::a
可以通过
moka
中的sub重新定义包A
中定义的sub。为此,有三个条件:
必须定义与MockA
相同的包李>A
必须包含在MockA
的所有包含内容之后李>A
- 警告<代码>重新定义不能是致命的
MockA.pm
可以是以下文件:
use strict;
# No fatal error if a sub is redefined
use warnings 'FATAL' => 'all', 'NONFATAL' => 'redefine';
# Override package A
package A;
sub a {
return "From mock";
}
1;
在单元测试中:
use B; # B includes A
use MockA; # MockA overrides A
B::to_test() # B calls MockA::a
现有的答案显示了如何替换模块的部分,这是非常明智的 但是,如果您想完全更换模块(甚至不需要安装原装模块),可以使用以下方法:
use strict;
# No fatal error if a sub is redefined
use warnings 'FATAL' => 'all', 'NONFATAL' => 'redefine';
# Override package A
package A;
sub a {
return "From mock";
}
1;
#使用我们正在模拟的包的名称。
A包;
...
#告诉Perl我们正在模拟的模块已经加载。
$INC{({uuuu PACKAGE}~s{::}{/}rg)。'.pm'}=1;
使用MockA代码>必须出现在的任何实例之前使用代码>现有答案显示了如何更换模块的部件,这是非常明智的
但是,如果您想完全更换模块(甚至不需要安装原装模块),可以使用以下方法:
use strict;
# No fatal error if a sub is redefined
use warnings 'FATAL' => 'all', 'NONFATAL' => 'redefine';
# Override package A
package A;
sub a {
return "From mock";
}
1;
#使用我们正在模拟的包的名称。
A包;
...
#告诉Perl我们正在模拟的模块已经加载。
$INC{({uuuu PACKAGE}~s{::}{/}rg)。'.pm'}=1;
使用MockA代码>必须出现在的任何实例之前使用
您可能也想查看Sub::Override。@simbabque我已经查看了这个模块,但没有找到任何方法来模拟整个包。有可能做到吗?没有,那只是做了和你在那里做的一样的事情,但是用更少的没有严格的s。MockModule基本上是一样的。你不想嘲笑整件事吧?你想在B中运行你的代码,并且你想为A中的调用为特定的B中的所有东西注入依赖项。你必须先加载真实的东西,否则它会覆盖你所做的更改。另一方面,一个正在做的事情是否涉及到外部依赖?或者它是否提供了对代码中分支的访问,而您只能通过更改其返回值来测试这些分支?您可能还需要查看Sub::Override。@simbabque我已经查看了这个模块,但没有找到任何方法来模拟整个包。有可能做到吗?没有,那只是做了和你在那里做的一样的事情,但是用更少的没有严格的s。MockModule基本上是一样的。你不想嘲笑整件事吧?你想在B中运行你的代码,并且你想为A中的调用为特定的B中的所有东西注入依赖项。你必须先加载真实的东西,否则它会覆盖你所做的更改。另一方面,一个正在做的事情是否涉及到外部依赖?或者它是否提供对代码中只能通过更改其返回值来测试的分支的访问?请尝试test::MockObject。是的,它与Test::MockModule有一个类似的名称,但它是一个不同的概念。两者都很有用,可以相互配合使用。但在您的示例中,真正的问题是缺少依赖注入。模块B不应该盲目地调用A::A()
。相反,您应该将一个对象传递给模块B,模块B应该执行$object->a()
。这样,您就可以提供一个轻量级的模拟对象,而不是真正的对象。是的,它与Test::MockModule有一个类似的名称,但它是一个不同的概念。两者都很有用,可以相互配合使用。但在您的示例中,真正的问题是缺少依赖注入。模块B不应该盲目地调用A::A()
。相反,您应该将一个对象传递给模块B,模块B应该执行$object->a()
。这样,您就可以提供一个轻量级的模拟对象,而不是真实的对象。