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


Is it possible to mock an object / function from a required class?

我试图测试我的一些php代码,但由于嘲笑对象而失败。我想模拟一个执行curl请求的函数,因为它不应该每次测试都执行请求。嘲笑旋度函数本身是有效的。为另一个类要求它并在那里嘲笑它是失败的。

以下是文件:

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函数应该被模拟,并返回给定的xml数据供_set函数继续使用。如何将$stubURL附加到$this->对象?无论如何可能吗?

谢谢你抽出时间。

据我所知,您需要将这样的mocking与自动加载结合使用。由于你对cURL助手有一个"硬"依赖(即class.request文件中的"require_one"),当它在代码中调用时,PHP将只看到真正的cURL类并使用它。如果使用自动加载,那么PHP可以拦截自动加载该类的调用并替换mock。

否则(这可能是一个更好的解决方案),您应该考虑某种IoC解决方案,通过这种解决方案,对cURL类的依赖性不会在请求类中硬编码(即,您不会直接在请求类中将cURL对象实例化)。实现这一点有多种方法。DI,或者更具体地说,依赖注入容器是PHP的当前趋势。您可能还需要查看服务定位器。马丁·福勒有一篇很好的文章描述了所有这些模式以及各种利弊。使用这两种模式中的任何一种,您都可以更容易地将测试对象(mock或stub等)替换为被测试的代码。