PHPUnit不能在mock对象上模拟__get函数

时间:2017-03-31 10:21:14

标签: php unit-testing mocking phpunit

我正在尝试为我的单元测试模拟一个mysqli对象,因此我必须直接模拟属性mysqli_result :: __ get()或模拟属性mysqli_result :: num_rows。 我已经找到了解决方案,但我找到的答案却没有用。

我的代码如下:

sudo dpkg -i StarUML-v2.8.0-64-bit.deb

当我运行该代码时,phpunit给出了以下错误消息:

  

C:\ xampp \ htdocs \ werimanage \ php> php phpunit-6.0.11.phar tests   Sebastian Bergmann和贡献者的PHPUnit 6.0.11。

     

PHP致命错误:方法Mock_mysqli_result_d3aa5482 :: __ get()必须在phar中使用1个参数:// C:/xampp/htdocs/werimanage/php/phpunit-6.0.11.phar/phpunit-mock-objects/Generator .php(263):第53行的eval()'代码

     

致命错误:方法Mock_mysqli_result_d3aa5482 :: __ get()必须在phar:// C:/xampp/htdocs/werimanage/php/phpunit-6.0.11.phar/phpunit-mock-objects/Generator中取1个参数。 php(263):第53行的eval()'

所以我不知道错误是什么或如何修复它。我将衷心感谢您的帮助。谢谢!

2 个答案:

答案 0 :(得分:1)

根据php文档,方法__get需要1个参数(更多的是这是phpUnit返回的错误)。

您可以在文档中看到:

  

public mixed __get ( string $name )

     

$ name参数的名称是   与之互动的财产。

我想你将在sql请求中调用列的__get方法。然后,您必须使用每个参数(每列)模拟所有调用和__get方法的返回。

希望这会对你有所帮助。

答案 1 :(得分:0)

发生此错误是因为魔术方法__get必须接受一个参数 - 属性的名称。当PHPUnit生成用于声明mock的代码时,它使用原始类中的方法声明。由于没有为__get声明mysqli_result的方法,因此PHPUnit模拟生成器将其声明为__get()而没有参数,这会遇到错误。

如果您真的想按照自己的方式进行编码和测试,可以使用以下方法:

class SuperMock extends mysqli_result {
    public function __get($name){

    }
}

class Mocks extends PHPUnit_Framework_TestCase
{
    public function testGet()
    {
        $data = ['one' => 1, 'two' => 2];
        $mock = $this->getMockBuilder('SuperMock')
                     ->disableOriginalConstructor()
                     ->setMethods(['__get', 'fetch_assoc'])
                     ->getMock();
        $mock->expects($this->once())
             ->method('__get')
             ->with('nonexistent')
             ->willReturn(42);
        $mock->expects($this->once())
             ->method('fetch_assoc')
             ->willReturn($data);
        $this->assertInstanceOf('mysqli_result', $mock);
        $this->assertSame(42, $mock->nonexistent);
        $this->assertSame($data, $mock->fetch_assoc());
    }

    public function testDirectProperty(){
        $mock = $this->getMockBuilder('SuperMock')
                     ->disableOriginalConstructor()
                     ->setMethods(['__get', 'fetch_assoc'])
                     ->getMock();
        $mock->nonexistent = 42;
        $this->assertSame(42, $mock->nonexistent);
    }
}

这将从技术上解决问题。我仍然建议修改你的测试策略。因为现在看起来您正在测试如何执行与数据库的交互。但是你真的需要测试数据是否作为关联数组被提取,并且通过mysqli_num_rows属性计算出这些行数?这样做会使测试过多地与生产代码相结合。我相信,当测试检索结果而不是此过程的内部细节更为充分时,就是这种情况。