【问题标题】:How to catch invalid query errors in unit-testing如何在单元测试中捕获无效查询错误
【发布时间】:2015-03-24 21:02:03
【问题描述】:

几个月前我在我们的开发过程中引入了单元测试。

我刚刚遇到了这个问题:我为一个简单的函数编写了一个测试用例,并且依赖于一个数据库查询。我使用了一个模拟对象而不是数据库适配器对象。测试通过了,到目前为止一切顺利。

但这是误报。模拟对象从数据库返回了预期的结果集(它必须,因为它是一个模拟对象),但真正的查询由于拼写错误而没有返回有效的结果集。

我可以解决此问题的一种方法是,如果查询未产生记录集,则引发异常。

$db->query($query);
$resultset = $db->fetchAll();
if(!is_array($resultset)) throw new UnexpectedValueException("Query does not yield a result set");

这种方法只会使整个脚本失败(如果没有捕获异常),测试肯定会失败。

我的问题是:这是正确的方法,还是您会推荐其他方法?

【问题讨论】:

    标签: php mysql database unit-testing mocking


    【解决方案1】:

    IMO 你的方法是错误的。为什么?

    1. 您没有测试模型是否能正确使用数据库(例如插入、更新或删除记录、选择记录)。

    2. 您无法检查查询是否正常。

    我们如何做到这一点?

    我们使用迁移系统 (https://github.com/ruckus/ruckusing-migrations),它允许我们轻松更改数据库。我们的系统有两个数据库 - 用于生产和测试。

    当我们创建新的更改(例如,使用一些更改列)时,我们会运行迁移,将更改应用到这些数据库。

    在测试中,我们使用在每次测试后回滚的事务。你可以看看这个 - https://github.com/letsdrink/ouzo/blob/master/src/Ouzo/Core/Tests/DbTransactionalTestCase.php(这是我们的框架),你可以看到有覆盖方法 setUptearDown 在每次测试后启动和回滚事务。您应该编写一个集成测试。

    这是如何工作的?

    具体的可以找example here

    public function shouldPersistModel()
    {
        //given
        $product = new Product();
        $product->name = 'Sport';
    
        //when
        $id = $product->insert();
    
        //then
        $this->assertNotNull($id);
        $actual = Product::findById($id);
        $this->assertEquals('Sport', $actual->name);
    }
    

    工作流程:

    1. 运行方法setUp 正在启动事务。
    2. 创建对象Product 并插入到数据库中。
    3. 获取具体对象。
    4. 断言。
    5. 运行方法tearDown 将数据库回滚到以前的状态。

    这里是link to the docs

    【讨论】:

    • 谢谢,这确实很有帮助。到目前为止,我阅读的所有单元测试介绍都建议模拟数据库适配器。你的方法更有意义。
    猜你喜欢
    • 2014-10-12
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2012-02-19
    相关资源
    最近更新 更多