如何在单元测试中捕获无效查询错误

How to catch invalid query errors in unit-testing

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

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

但这是误报。模拟对象 return 从数据库中编辑了预期的结果集(它必须,因为它是模拟对象),但由于拼写错误,真实查询没有 return 有效的结果集。

我可以解决这个问题的一种方法是在查询没有产生记录集时抛出异常。

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

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

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

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