【问题标题】:Unit testing with mocks (PHP)使用模拟进行单元测试 (PHP)
【发布时间】:2012-02-16 21:14:36
【问题描述】:

我有这样的课程:

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

        return $model;
    }
}

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

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

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

【问题讨论】:

    标签: php unit-testing dependency-injection


    【解决方案1】:

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

    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());
    

    其中MockQuery 是您的Query 类的模拟版本,它返回模拟条形

    【讨论】:

    • 我正在使用 Propel for PHP,注入一个模拟的 Propel Query 对象会感觉很奇怪,是吗?
    • @rFactor 我同意,DI 确实感觉很奇怪。您将事物传递给不完全属于正在创建的对象的构造函数,但好处超过了奇怪之处。顺便说一句,Propel 开发人员在测试方面很投入 - 如果他们没有办法嘲笑事物,我会感到惊讶。
    【解决方案2】:

    您可以尝试使用dependency injection

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

    class Foo
    {
        private _bar;
    
        function __construct (Bar $bar)
        {
            $this->_bar = $bar;
        }
    
        public function getCurrentBar()
        {
            return $this->_bar;
        }
    }
    

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

    【讨论】:

      【解决方案3】:

      您还可以选择测试部分模拟对象,作为 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();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-04
        • 2013-11-12
        • 2018-11-21
        相关资源
        最近更新 更多