【问题标题】:Returning Different Results in PHPUnit Mock Object在 PHPUnit 模拟对象中返回不同的结果
【发布时间】:2012-10-03 09:17:48
【问题描述】:

我一直在努力让我们的系统与 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() 中只包含奇数值,但这有同样的问题,我尝试让它返回 at(1-2) 的数据,但这只是将所有数据传递到第一个 while 循环,另一个没有。

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

【问题讨论】:

    标签: php mocking phpunit


    【解决方案1】:

    我无法运行代码,因为它似乎只是伪代码,但据我了解,您正在尝试像这样模拟:

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

    您似乎遇到的问题是 ->at() 匹配器中的数字不是按 method 而是按 object 计数的

    所以你可能想写的是:

        $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);

    【讨论】:

    • 很抱歉延迟响应,已转移到另一个项目,但应该能够很快回到这个项目。这看起来可能是问题所在,如果它有效,会通知您
    • 这完成了工作,我认为 at() 的索引是相对于方法的,而不是对象的,所以它跳过了过程的“查询”部分。另外,很抱歉没有发布有效的代码。它基于我使用的代码,但被编写为简化版本,在发布之前我没有机会对其进行测试
    【解决方案2】:

    不幸的是,at() 将您的测试与实现非常紧密地绑定在一起。

    想象一下,如果您在一个测试方法中重新安排了 2 个方法调用,其功能完全相同相同,但所有使用 at() 的测试现在都会失败,通常会出现诸如 method doesn't exist at index N 之类的神秘消息 p>

    如果你想明确地说“这就是这样调用,然后就是这样调用”,这很好,但如果你只是想要断言,那么 PHPUnit 模拟扩展之一似乎更友好,特别是 Mockery 和指导here(我认为有点过时了)

    还有其他的。

    【讨论】:

    • edorian 的解决方案解决了这个问题,但会看看 Mockery 看看是否可以使用。在这方面有更大的灵活性会很有用。感谢您的信息
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    • 1970-01-01
    • 2016-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多