我发现了关于你是否测试私有方法的讨论。
我已经决定,在某些类中,我希望有受保护的方法,但要测试它们。
其中一些方法是静态的和简短的。因为大多数公共方法都使用了这些测试,所以我以后可能会安全地删除这些测试。但是为了从TDD方法开始并避免调试,我真的很想测试它们。
我想到了以下几点:
在回答中建议的方法对象似乎是多余的。
从公共方法开始,当代码覆盖由更高级别的测试提供时,将它们变为受保护的,并删除测试。
继承一个具有可测试接口的类,该接口使受保护的方法公开
哪种是最佳实践?还有别的事吗?
看起来,JUnit会自动将受保护的方法更改为公共方法,但我并没有深入了解它。PHP不允许通过反射进行此操作。
You seem to be aware already, but I'll just restate it anyway; It's a bad sign, if you need to test protected methods. The aim of a unit test, is to test the interface of a class, and protected methods are implementation details. That said, there are cases where it makes sense. If you use inheritance, you can see a superclass as providing an interface for the subclass. So here, you would have to test the protected method (But never a private one). The solution to this, is to create a subclass for testing purpose, and use this to expose the methods. Eg.:
class Foo {
protected function stuff() {
// secret stuff, you want to test
}
}
class SubFoo extends Foo {
public function exposedStuff() {
return $this->stuff();
}
}
注意,您总是可以用组合替换继承。在测试代码时,处理使用这种模式的代码通常要容易得多,因此您可能需要考虑该选项。
You seem to be aware already, but I'll just restate it anyway; It's a bad sign, if you need to test protected methods. The aim of a unit test, is to test the interface of a class, and protected methods are implementation details. That said, there are cases where it makes sense. If you use inheritance, you can see a superclass as providing an interface for the subclass. So here, you would have to test the protected method (But never a private one). The solution to this, is to create a subclass for testing purpose, and use this to expose the methods. Eg.:
class Foo {
protected function stuff() {
// secret stuff, you want to test
}
}
class SubFoo extends Foo {
public function exposedStuff() {
return $this->stuff();
}
}
注意,您总是可以用组合替换继承。在测试代码时,处理使用这种模式的代码通常要容易得多,因此您可能需要考虑该选项。
你确实可以以通用的方式使用__call()来访问受保护的方法。以便能够测试这个类
class Example {
protected function getMessage() {
return 'hello';
}
}
在ExampleTest.php中创建一个子类:
class ExampleExposed extends Example {
public function __call($method, array $args = array()) {
if (!method_exists($this, $method))
throw new BadMethodCallException("method '$method' does not exist");
return call_user_func_array(array($this, $method), $args);
}
}
注意,__call()方法不会以任何方式引用类,所以你可以将上面的方法复制到每个你想测试的受保护方法的类中,只需要更改类声明。您可以将此函数放在公共基类中,但我还没有尝试过。
现在,测试用例本身的不同之处在于您在哪里构造要测试的对象,例如交换ExampleExposed。
class ExampleTest extends PHPUnit_Framework_TestCase {
function testGetMessage() {
$fixture = new ExampleExposed();
self::assertEquals('hello', $fixture->getMessage());
}
}
我相信PHP 5.3允许您使用反射来直接更改方法的可访问性,但我假设您必须对每个方法单独这样做。