我想单元测试官方段PHP集成的包装类。因此,我将不得不用嘲弄模拟细分市场,以便不会有任何真正的API请求。
问题
模拟的类仅由静态方法组成。因此,我试图像这样模拟它(与别名(:
$segment = Mockery::mock('alias:Segment');
这起作用,但前提是班级没有由作曲家自动加载。如果我加载它 - 就像我必须对应用程序的其余部分一样 - 我将获得错误
Could not load mock Segment, class already exists.
(这是有道理的,因为文档指出在之前不得加载别名类。(
问题
我如何嘲笑这个(邪恶?(班,但仍然像往常一样在我的应用程序中使用它?
本质上,您不能用静态调用模拟类。
静态调用始终准确地引用要调用的类和方法,这等同于指向要执行的文件和代码行(如果您假设基本自动加载功能可用(。
执行不同代码的唯一方法是不包括原始类,而是首先加载模拟类代码。您是否有替代代码文件,或者是使用嘲弄调用eval()
都没有关系。两种方式都可以。
,但它们也只能工作一次。您不能在以后的测试中切换回原始代码,因为每次运行一次只能定义一类。并且无法切换实现(例如原始与模拟与另一个模拟(是问题所在。
该解决方案在评论中也提到:没有具有静态方法的类。始终创建类实例并调用动态方法。这样,您可以轻松模拟该类,但是它需要首先创建一个实例,并提供一种将类(或至少是模拟类(注入您要测试的代码的方法。
作为一种通用模式,如果项目中没有依赖项注入,我正在使用此
(我有时必须处理一些遗产的东西(:
public function __construct(MyClass $class = null) {
$this->class = $class ?: new MyClass();
}
这样,我不必注入课程,但是我能够注入模拟而不是真实的班级。
对于可用依赖注入的情况,构造函数将是一个非常基本的初始化器:
public function __construct(MyClass $class) {
$this->class = $class;
}
如果您的依赖注入框架能够进行自动接线(例如PHP-DI(,并且您只有一个MyClass
,那么这效果很好,因为这将自动注入,而无需定义任何内容。