如何单元测试方法,你不能注入依赖

时间:2014-12-23 14:05:21

标签: php unit-testing phpunit

我有以下代码:

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()方法吗?

这听起来也不是很好,因为我正在编写额外的代码只是为了对这个类进行单元测试!

1 个答案:

答案 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关键字。这可能是一个私人细节 - 然后你不需要对它进行单元测试 - 或者它不是,那么你应该将它作为一个依赖项,或者它应该是公共接口的一部分,如果它是公开的。