在PHPUnit Mock对象中返回不同的结果

时间:2012-10-03 09:17:49

标签: php mocking phpunit

我一直在努力让我们的系统与PHPUnit更兼容,所以我们可以对我们的类进行更多的单元测试,并设法使其中一些使用模拟对象,但我遇到了一个问题,我可以似乎没事。

我们拥有的一个类(我正在创建一个模拟版本)用于查询。您将查询字符串传递给它的“query()”方法,它会记录查询,运行它并返回结果。它还使用一个名为“get_row()”的方法包装mysql_fetch_assoc,该方法返回一个与原始数据非常相似的数组值。

问题在于,在某些方法中,有多个查询被传递给“query()”方法,因此需要运行多个while循环才能将数据加载到不同的变量中。我在下面创建了一个简化版本:

class object{
    public function __construct($query){
        $this->query = $query;
    }

    public function loadData(){

        $data1 = queryDataSource("SELECT * FROM data1");
        $data2 = queryDataSource("SELECT * FROM data2");

        return Array(
            "data1" => $data1,
            "data2" => $data2,
        );

    }

    private function queryDataSource($query){
        $this->query->query($query)

        while($row = $this->query->get_row()){
            $result[] = $row;
        }

        return $result
    }
}

class testObject extends PHPUnit_Framework_TestCase{
    method testLoadData(){
        $test_data = Array('name' => 'Bob', 'number' => '98210');

        $query = $this->getMock('Query');
        $query->expects($this->any())->method('query');
        $query->expects($this->at(1))->method('get_row')->will($this->returnValue($test_data);
        $query->expects($this->at(2))->method('get_row')->will($this->returnValue(False);
        $query->expects($this->at(3))->method('get_row')->will($this->returnValue($test_data);
        $query->expects($this->at(4))->method('get_row')->will($this->returnValue(False);
    }
}

为了逃避$ object-> queryDataSource()中的第一个while循环,我返回一个布尔值FALSE值,就像执行mysql_fetch_assoc时一样。问题是,当它试图运行第二个查询并通过get_row()获取数据时,模拟对象似乎继续返回FALSE ratehr而不是继续到at(3)点。即使有4个对象也会发生这种情况,只有第一个将测试数据作为返回值,然后第二次得到FALSE,其他的每次都会得到FALSE。

有谁知道是否有办法解决这个问题?我尝试删除FALSE标志,只是在()中有奇数值,但是有同样的问题,我试着让它返回at(1-2)的数据,但是这只是将所有数据传递给了第一次是循环而另一种没有。

感谢您提供的任何帮助,希望问题的描述足够清楚

2 个答案:

答案 0 :(得分:7)

我无法运行代码,因为它似乎只是伪代码,但据我所知,你试图像这样嘲笑:

Call to query, get_row, get_row, query, get_row, get_row.

您似乎遇到的问题是 ->at()匹配器中的数字不会按method计算,而是按object 计算。< / p>

所以你可能想写的是:

    $query->expects($this->any())->method('query');
    $query->expects($this->at(1))->method('get_row')->will($this->returnValue($test_data);
    $query->expects($this->at(2))->method('get_row')->will($this->returnValue(False);
    $query->expects($this->at(4))->method('get_row')->will($this->returnValue($test_data);
    $query->expects($this->at(5))->method('get_row')->will($this->returnValue(False);

或者甚至让它成为一个轻松的阅读器:

    $query->expects($this->at(0))->method('query');
    $query->expects($this->at(1))->method('get_row')->will($this->returnValue($test_data);
    $query->expects($this->at(2))->method('get_row')->will($this->returnValue(False);
    $query->expects($this->at(3))->method('query');
    $query->expects($this->at(4))->method('get_row')->will($this->returnValue($test_data);
    $query->expects($this->at(5))->method('get_row')->will($this->returnValue(False);

使用你的模拟你遇到的问题是第二次调用“查询”正在计算一个“调用”,因此跳过第二个return($test_data);

答案 1 :(得分:1)

不幸的是,at()非常强烈地将您的测试绑定到实现。

想象一下,如果你在一个经过测试的方法中重新安排了两个方法调用,那么功能完全相同,但是使用at()的所有测试现在都会失败,通常会使用{{1 }}

在你想要特别说“这就是这样调用然后这就是这样调用”的情况下,这很好,但是如果你只是想要断言那么PHPUnit Mock Extensions之一似乎更友好,特别是Mockery和指南here(我相信过时了)

还有其他人。