模拟全局静态方法的最佳方法
best way to mock a global static method
我的应用程序有一个带有签名的记录器库:
final class Logger {
public static method debug($msg);
public static method warn($msg);
public static method error($msg);
}
我要测试的class,另一个全局静态助手,将其用作
final class TestMe {
public static method TestThis(){
Logger::debug('TestThis() called');
doThings();
}
}
如何通过模拟 Logger
并等待预期消息来测试 TestMe
class?
如果您使用的是像 PHPUnit 这样的测试框架,它提供了模拟对象的能力。您可以为您的记录器 class 创建一个模拟对象并在其中定义调试方法。
这里有详细的解释:
https://phpunit.de/manual/current/en/test-doubles.html
这是从该页面摘取的一个小例子:
<?php
require_once 'SomeClass.php';
class StubTest extends PHPUnit_Framework_TestCase
{
public function testStub()
{
// Create a stub for the SomeClass class.
$stub = $this->getMockBuilder('SomeClass')
->getMock();
// Configure the stub.
$stub->method('doSomething')
->willReturn('foo');
// Calling $stub->doSomething() will now return
// 'foo'.
$this->assertEquals('foo', $stub->doSomething());
}
}
?>
PHPUnit 无法模拟您的记录器 class 有几个原因。
- class 列为
final
表示无法扩展。当 PHPUnit 创建一个对象的 mock 时,它会创建一个扩展被模拟的 class 的新对象。 final
关键字阻止扩展 class,因此无法创建模拟。
- 正在静态调用您要替换的方法。您无法替换它们,因为调用被定向到实际的 class。 PHPUnit 5.3 has a way of "mocking" static methods but that is only within the class being called statically. 它不会替换来自 class.
外部的调用
http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
你有两个选项来测试这样的事情:
- 扩大您正在测试的行为的范围。断言
Logger
class 所做的一切都已完成。这将使任何测试都不再是 "unit" 测试,但它们确实封装了预期的行为并且仍然有用。
- 重构您的用法以使用依赖项注入,以便您可以传入不静态调用方法的
mockLogger
。这可能会更痛苦,但会使您的代码更灵活 IMO。
我的应用程序有一个带有签名的记录器库:
final class Logger {
public static method debug($msg);
public static method warn($msg);
public static method error($msg);
}
我要测试的class,另一个全局静态助手,将其用作
final class TestMe {
public static method TestThis(){
Logger::debug('TestThis() called');
doThings();
}
}
如何通过模拟 Logger
并等待预期消息来测试 TestMe
class?
如果您使用的是像 PHPUnit 这样的测试框架,它提供了模拟对象的能力。您可以为您的记录器 class 创建一个模拟对象并在其中定义调试方法。
这里有详细的解释:
https://phpunit.de/manual/current/en/test-doubles.html
这是从该页面摘取的一个小例子:
<?php
require_once 'SomeClass.php';
class StubTest extends PHPUnit_Framework_TestCase
{
public function testStub()
{
// Create a stub for the SomeClass class.
$stub = $this->getMockBuilder('SomeClass')
->getMock();
// Configure the stub.
$stub->method('doSomething')
->willReturn('foo');
// Calling $stub->doSomething() will now return
// 'foo'.
$this->assertEquals('foo', $stub->doSomething());
}
}
?>
PHPUnit 无法模拟您的记录器 class 有几个原因。
- class 列为
final
表示无法扩展。当 PHPUnit 创建一个对象的 mock 时,它会创建一个扩展被模拟的 class 的新对象。final
关键字阻止扩展 class,因此无法创建模拟。 - 正在静态调用您要替换的方法。您无法替换它们,因为调用被定向到实际的 class。 PHPUnit 5.3 has a way of "mocking" static methods but that is only within the class being called statically. 它不会替换来自 class. 外部的调用
http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
你有两个选项来测试这样的事情:
- 扩大您正在测试的行为的范围。断言
Logger
class 所做的一切都已完成。这将使任何测试都不再是 "unit" 测试,但它们确实封装了预期的行为并且仍然有用。 - 重构您的用法以使用依赖项注入,以便您可以传入不静态调用方法的
mockLogger
。这可能会更痛苦,但会使您的代码更灵活 IMO。