为了创建用于单元测试的全局函数的模拟版本,我在SUT类的名称空间中定义了它的模拟版本,如here所解释的
考虑在命名空间Bar
和命名空间Baz
中使用的全局函数foo()
的情况。如果我想在这两个地方使用相同的foo()
模拟版本,似乎我必须为foo()
做两个模拟声明
/* bar-namespace-mocks.php */
namespace Bar;
function foo(){
return 'foo mock';
}
/* baz-namespace-mocks.php */
namespace Baz;
function foo(){
return 'foo mock';
}
此代码不符合DRY principal。最好有一个foo mock的声明
/* foo-mock.php */
function foo(){
return 'foo mock';
}
然后根据需要导入到每个命名空间,如以下伪代码:
/* namespace-mocks.php */
namespace Bar{
import 'foo-mock.php';
}
namespace Baz{
import 'foo-mock.php';
}
使用include导入,例如
namespace Baz;
include 'foo-mock.php'
不会导致在Baz
命名空间中声明mock。有没有办法在多个命名空间中声明一个函数,而不需要多个版本?
2条答案
按热度按时间7dl7o3gd1#
如果你需要抽象出一个原生函数,那么为它创建一个合约,这样你就可以对它提供的服务使用依赖注入:
然后提供一个使用本机函数的默认实现:
然后你的主类可能看起来像这样:
所以,你在构造函数中有一个可选参数,如果你不提供一个值,你将获得原生的foo函数作为默认值。你只需要做:
但是如果你想覆盖它,你可以这样做:
然后,在你的测试中,你可以构建一个显式的mock:
并在此示例中通过:
或者使用PHPUnit模拟构建器:
如果你想要一个更简单的版本,你可以只使用一个callable:
pkln4tw62#
虽然我完全同意Alex Howansky的回答,但如果你真的执意要使用普通函数,那么你总是可以:
输出:
虽然在这一点上,我们真的只是在重新发明类的路上,但更糟。在某个时候,你会想知道如何命名一个变量,这是不可能的,所以你会在这一点上滚动到类。
类、接口和traits/继承是解决这个问题最合适的工具。