我有以下代码:
class Plugin {
protected $manager;
public function activate(Composer $composer, IOInterface $io)
{
$this->manager = new Manager();
$this->doSomething($this->manager);
}
private function doSomething(Managaer $manager)
{
$manager->add('first', function() {
//do something.
});
$manager->add('second', function() {
//do something.
});
}
}
如何声明在add
类上调用Manager
方法?
Plugin
类是为我实例化的,不能注入依赖项。我也调用了activate方法(不在我的控件中),因此我无法传递依赖项。
我通常通过使用以下额外方法对其进行测试并模拟它以返回Manager
的模拟实例
class Plugin {
protected $manager;
public function activate(Composer $composer, IOInterface $io)
{
$this->doSomething($this->getManager());
}
private function doSomething(Manager $manager)
{
$manager->add('first', function() {
//do something.
});
$manager->add('second', function() {
//do something.
});
}
public function getManager()
{
return new Manager;
}
}
这看起来如下:
//get a mock manager
$manager = $this->getMock('Manager');
//assert that method should be called
$manager->expects($this->once())
->method('add')
->with($this->isInstanceOf('Closure'));
//create mock plugin but only mock getManager method
$plugin = $this->getMock('Plugin');
$plugin->expects($this->once())
->method('getManager')
->will($this->returnValue($manager));
$plugin->activate(/** args **/);
这对我来说,感觉很难过。我觉得我不应该嘲笑Plugin
课程。其他人如何解决这个问题?
你有一个二传手和一个经理的吸气剂?如果未设置类变量,则返回默认实例。这样在测试中我可以用模拟实例调用setManager()
方法吗?
这听起来也不是很好,因为我正在编写额外的代码只是为了对这个类进行单元测试!
答案 0 :(得分:2)
如果您不想直接修改正在测试的Plugin
课程,只需创建一些方法将经理模拟注入其中:
class PluginTester extends Plugin
{
public function setManager(Plugin $plugin, Manager $manager) {
$plugin->manager = $manager;
}
}
然后你可以用它来注入模拟:
$plugin = new Plugin();
$stubManager = new ManagerMock();
$util = new PluginTester();
$util->setManager($plugin, $stubManager);
或者,如果您确实需要模拟这些对象,请不要在内部或您的类中使用new
关键字。这可能是一个私人细节 - 然后你不需要对它进行单元测试 - 或者它不是,那么你应该将它作为一个依赖项,或者它应该是公共接口的一部分,如果它是公开的。