8

这是我正在为其编写测试套件的类的构造函数(它扩展了 mysqli):

function __construct(Config $c)
{
    // store config file
    $this->config = $c;

    // do mysqli constructor
    parent::__construct(
        $this->config['db_host'],
        $this->config['db_user'],
        $this->config['db_pass'],
        $this->config['db_dbname']
    );
}

Config传递给构造函数的类实现了arrayaccessphp内置的接口:

class Config implements arrayaccess{...}

如何模拟/存根Config对象?我应该使用哪个,为什么?

提前致谢!

4

2 回答 2

16

Config如果您可以轻松地从数组创建实例,那将是我的首选。虽然您想在可行的情况下单独测试您的单元,但简单的协作者(例如)Config应该足够安全以在测试中使用。设置它的代码可能比等效的模拟对象更容易读写(不易出错)。

$configValues = array(
    'db_host' => '...',
    'db_user' => '...',
    'db_pass' => '...',
    'db_dbname' => '...',
);
$config = new Config($configValues);

话虽如此,你模拟一个对象的实现ArrayAccess就像你模拟任何其他对象一样。

$config = $this->getMock('Config', array('offsetGet'));
$config->expects($this->any())
       ->method('offsetGet')
       ->will($this->returnCallback(
           function ($key) use ($configValues) {
               return $configValues[$key];
           }
       );

您还可以使用at来强制执行特定的访问顺序,但是这样会使测试变得非常脆弱。

于 2012-05-15T23:32:51.343 回答
1

问这个问题 8 年后,第一次回答这个问题 5 年后,我有同样的问题并得出了类似的结论。这就是我所做的,这与大卫接受的答案的第二部分基本相同,只是我使用的是更高版本的 PHPUnit。

基本上你可以模拟ArrayAccess接口方法。只需要记住你可能想要同时模拟offsetGetoffsetExists(你应该在使用之前检查数组键是否存在,否则E_NOTICE如果它不存在,你可能会在代码中遇到错误和不可预知的行为)。



$thingyWithArrayAccess = $this->createMock(ThingyWithArrayAccess::class);

$thingyWithArrayAccess->method('offsetGet')
     ->with('your-offset-here')
     ->willReturn('test-value-1');

$thingyWithArrayAccess->method('offsetExists')
     ->with($'your-offset-here')
     ->willReturn(true);

当然,您可以在测试中使用真正的数组,例如


$theArray = [
    'your-offset-here-1' => 'your-mock-value-for-offset-1',
];

$thingyWithArrayAccess = $this->createMock(ThingyWithArrayAccess::class);

$thingyWithArrayAccess->method('offsetGet')
     ->willReturnCallback(
          function ($offset) use ($theArray) {
              return $theArray[$offset];
          }
     );

$thingyWithArrayAccess->method('offsetExists')
     ->willReturnCallback(
          function ($offset) use ($theArray) {
              return array_key_exists($offset, $theArray);
          }
     );

于 2020-07-29T16:33:23.310 回答