PHP 单元测试 - 使用 Mockery 自动加载模拟静态 class
PHP Unit Testing - Mock static autoloaded class with Mockery
我想对官方 Segment PHP 集成的包装器 class 进行单元测试。因此,我将不得不使用 Mockery 模拟 the Segment class,这样就不会有任何真正的 API 请求。
问题
要模拟的 class 仅包含静态方法。因此,我尝试像这样模拟它(使用 alias):
$segment = Mockery::mock('alias:Segment');
这有效,但前提是 class 没有被作曲家自动加载。如果我加载它 - 就像我必须为应用程序的其余部分一样 - 我会收到错误
Could not load mock Segment, class already exists.
(这是有道理的,因为文档声明之前不得加载别名 class。)
问题
我怎样才能嘲笑这个(邪恶的?)class,但仍然像往常一样在我的应用程序的其余部分中使用它?
本质上,您不能使用静态调用模拟 classes。
静态调用始终准确引用 class 和要调用的方法,这相当于准确指向要执行的文件和代码行(如果您假设基本的自动加载功能可用)。
执行不同代码的唯一方法是不包含原始 class,而是首先加载模拟 class 代码。如果您有替代代码文件,或者您是否使用 Mockery 调用 eval()
,都没有关系。两种方式都可以。
但它们也只能工作一次。您不能在以后的测试中切换回原始代码,因为每个脚本 运行 只能定义一次 class。无法切换实现(如原始与模拟与另一个模拟)是这里的问题。
解决方案,评论中也提到了:Don't have classes with static methods。始终创建 classes 的实例并调用动态方法。通过这种方式,您可以轻松模拟 class,但它需要先创建一个实例,并提供一种将 class(或至少模拟的 class)注入代码的方法想测试一下。
如果依赖注入在项目中不可用,我将使用它作为通用模式(有时我必须处理一些遗留问题):
public function __construct(MyClass $class = null) {
$this->class = $class ?: new MyClass();
}
这样我就不必注入 class,但我可以注入模拟而不是真实的 class。
对于依赖注入可用的情况,构造函数将是一个非常基本的初始化器:
public function __construct(MyClass $class) {
$this->class = $class;
}
如果您的依赖注入框架能够进行自动连接(如 PHP-DI),并且您只有一个 MyClass
,这将非常有用,因为它会在没有您的情况下自动注入必须定义任何东西。
我想对官方 Segment PHP 集成的包装器 class 进行单元测试。因此,我将不得不使用 Mockery 模拟 the Segment class,这样就不会有任何真正的 API 请求。
问题
要模拟的 class 仅包含静态方法。因此,我尝试像这样模拟它(使用 alias):
$segment = Mockery::mock('alias:Segment');
这有效,但前提是 class 没有被作曲家自动加载。如果我加载它 - 就像我必须为应用程序的其余部分一样 - 我会收到错误
Could not load mock Segment, class already exists.
(这是有道理的,因为文档声明之前不得加载别名 class。)
问题
我怎样才能嘲笑这个(邪恶的?)class,但仍然像往常一样在我的应用程序的其余部分中使用它?
本质上,您不能使用静态调用模拟 classes。
静态调用始终准确引用 class 和要调用的方法,这相当于准确指向要执行的文件和代码行(如果您假设基本的自动加载功能可用)。
执行不同代码的唯一方法是不包含原始 class,而是首先加载模拟 class 代码。如果您有替代代码文件,或者您是否使用 Mockery 调用 eval()
,都没有关系。两种方式都可以。
但它们也只能工作一次。您不能在以后的测试中切换回原始代码,因为每个脚本 运行 只能定义一次 class。无法切换实现(如原始与模拟与另一个模拟)是这里的问题。
解决方案,评论中也提到了:Don't have classes with static methods。始终创建 classes 的实例并调用动态方法。通过这种方式,您可以轻松模拟 class,但它需要先创建一个实例,并提供一种将 class(或至少模拟的 class)注入代码的方法想测试一下。
如果依赖注入在项目中不可用,我将使用它作为通用模式(有时我必须处理一些遗留问题):
public function __construct(MyClass $class = null) {
$this->class = $class ?: new MyClass();
}
这样我就不必注入 class,但我可以注入模拟而不是真实的 class。
对于依赖注入可用的情况,构造函数将是一个非常基本的初始化器:
public function __construct(MyClass $class) {
$this->class = $class;
}
如果您的依赖注入框架能够进行自动连接(如 PHP-DI),并且您只有一个 MyClass
,这将非常有用,因为它会在没有您的情况下自动注入必须定义任何东西。