是否可以从必需的类中模拟对象/函数?

时间:2012-02-24 13:33:28

标签: php mocking phpunit

我正在尝试测试我的一些PHP代码,但是使用模拟对象失败了。我想模拟一个执行curl请求的函数,因为它不应该每次/ test都执行请求。嘲弄卷曲功能本身,有效。要求它用于另一个课程并在那里嘲笑它,就失败了。

以下是文件:

helper.curl.php:

  class Helper_Curl {

    /*
    ** __construct($callDomain) - construct new curl helper using set calldomain
    */
    public function __construct($callDomain) {
      $this->callDomain = $callDomain;
    }

    /*
    ** sendPostArrayToApi($Array) - HTTP POST request to server
    */
    public function sendPostArrayToApi($Array) {

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $this->callDomain);
      // [... curl Settings ...]
      $return = curl_exec($ch);
      curl_close($ch);
      return $return;
    }     
  }

class.request.php

  require_once('helper.curl.php');

  class RequestClass {

    function _set($data, $set_type='edit'){

      // [... some code ...]

      $curl = new Helper_Curl('http://example.com');
      $xml = $curl->sendPostArrayToApi($InfoArray);

      if($xml == "") {
        return false;
      }
      // [... some more code ...]
    }     
  }

最后测试:

  class ClassRequestTest extends PHPUnit_Framework_TestCase {

    public function setUp() {
      require_once('class.request.php');
    }

    public function testSetRefund() {

      $xml = '<?xml version="1.0" encoding="UTF-8"?>
              <response>
                <info-id>12345</info-id>
                <transmit-id>315</transmit-id>
              </response>';

      $stubCurl = $this->getMock('Helper_Curl');

      $stubCurl->expects($this->once())
               ->method('sendPostArrayToApi')
               ->will($this->returnValue($xml));

      $this->object->_set($DataArray);
    }

    protected function tearDown() {
      unset($this->object);
    }
  }

应该模拟Helper_Curl类中的sendPostArrayToApi函数,并返回给定的_set函数的给定xml数据。如何将$ stubCurl附加到$ this-&gt;对象?无论如何可能吗?

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

据我所知,你需要在自动加载的同时使用这样的模拟。由于你在cURL帮助器上有一个“硬”依赖(即你的class.request文件中的“require_once”),当它在代码中调用时,PHP只会看到真正的cURL类并将使用它。如果你使用自动加载,那么PHP可以拦截对该类的自动加载的调用并替换模拟。

否则(这可能是一个更好的解决方案),您应该查看某种IoC解决方案,其中对cURL类的依赖不会在您的请求类中进行硬编码(即您不实例化直接在请求类中的cURL对象)。有多种方法可以实现这一目标。 DI或者更具体地说,依赖注入容器是PHP的当前趋势。您可能还想查看Service Locator。有good article by Martin Fowler描述了所有这些模式以及各种利弊。使用这些模式中的任何一种,您都可以更轻松地将测试对象(模拟或存根等)替换为测试中的代码。