使用模拟进行单元测试(PHP)

时间:2012-01-23 14:17:42

标签: php unit-testing dependency-injection

我有一个类:

class Foo {
    function getCurrentBar() {
        $model = Query::findByPk($this->getSession()->get('current_bar')); // Pseudocode...

        return $model;
    }
}

所以基本上我的应用程序中一次只有一个栏,它作为整数存储在会话中。我经常调用一个辅助函数来查找模型实例,它会进行数据库查询。还有缓存,但现在没关系。

我的问题是:我如何用对进行单元测试?我测试的类需要这个。我想我可以改变会话以包含id但是这意味着我需要在数据库中有相应的模型。

最佳方法是仅为单元测试添加方法setCurrentBar()吗?然后我可以模拟一个条形对象并设置它,它将用于所有单元测试。这有意义吗?

3 个答案:

答案 0 :(得分:6)

答案确实是依赖注入,但你想要控制的依赖是吧的,而不是吧本身。

class Foo {
  private $query;

  function __construct($query)
  {
    $this->query = $query;
  }

  function getCurrentBar() {
    $model = $this->query->findByPk($this->getSession()->get('current_bar')); // Pseudocode...

    return $model;
  }
}

所以在你的生产代码中你有

$query = new Query() // assuming findByPk() is made a normal non-static method
$realFoo = new Foo($query);

但是对于单元测试...

$testFoo = new Foo(new MockQuery());

其中MockQueryQuery类的模拟版本,它返回mock bars

答案 1 :(得分:0)

您可以尝试使用dependency injection

将Bar实例传递给Foo构造函数

class Foo
{
    private _bar;

    function __construct (Bar $bar)
    {
        $this->_bar = $bar;
    }

    public function getCurrentBar()
    {
        return $this->_bar;
    }
}

然后,您可以在运行测试时注入模拟Bar对象。

答案 2 :(得分:0)

您也可以选择测试部分模拟对象,直到DI系统到位为止。

class Foo {
    function getCurrentBar() {
        $model = $this->getQueryResult($this->getSession()->get('current_bar')); // Pseudocode...
        return $model;
    }
    function getQueryResult($queryParams)
    {
        return Query::findByPk($queryParams);
    }
}

然后做一个看起来有点像这样的测试...

$myObjectToTest = $this->getMock('Foo', array('getQueryResult'), array(), '', true, true, true);
$myObjectToTest->expects($this->once())
               ->method('getQueryResult')
               ->with($whateverTheQueryParametersAre)
               ->will($this->returnValue($someResult));
$myObjectToTest->getCurrentBar();