【问题标题】:Mocking/Stubbing an Object of a class that implements arrayaccess in PHPUnit模拟/存根在 PHPUnit 中实现数组访问的类的对象
【发布时间】:2012-05-23 08:16:30
【问题描述】:

这是我正在为其编写测试套件的类的构造函数(它扩展了 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类实现了php内置的arrayaccess接口:

class Config implements arrayaccess{...}

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

提前致谢!

【问题讨论】:

    标签: php phpunit arrayaccess


    【解决方案1】:

    如果您可以轻松地从数组创建 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 来强制执行特定的访问顺序,但这样会使测试变得非常脆弱。

    【讨论】:

    • 你甚至可以轻松地做到这一点,但使用数组:-)
    【解决方案2】:

    在提出问题 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);
              }
         );
    
    

    【讨论】:

    • 哇,过去的大爆炸!自从我在 PHP 中工作以来,已经差不多有这么长的时间了。
    猜你喜欢
    • 2011-12-26
    • 2013-04-27
    • 2012-09-26
    • 2018-02-08
    • 2021-10-31
    • 2011-10-28
    • 2015-03-23
    • 2015-08-12
    • 1970-01-01
    相关资源
    最近更新 更多