duanben1909 2015-01-26 12:40
浏览 34
已采纳

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

I introduced unit-testing a few month ago in our development process.

I just faced this problem : I wrote a test case for a simple function and relies on a database query. I used a mock object instead of the database adapter object. The tests passed, so far so good.

But it was a false positive. The mock object returned the expected resultset form the database (it must, since it is a mock object), but the real query did not return a valid resultset because of a typo.

One way I could solve this problem is to throw an exception if the query does not yield a recordset.

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

This approach just makes the whole script fail (if the exception is not catched), and the test will fail for sure.

My question is : Is this the correct approach, or would you recommend something else ?

  • 写回答

1条回答 默认 最新

  • doujing5150 2015-01-26 21:32
    关注

    IMO your approach is wrong. Why?

    1. You do not test that models correctly working with database (e.g. insert, update or delete records, selecting records).

    2. You can't check the queries are OK.

    How we do this?

    We use migrations system (https://github.com/ruckus/ruckusing-migrations) that allows us to change databases easily. Our system has two databases - for production and for tests.

    When we create a new change (e.g. with some alter column) we run migration which apply changes to these databases.

    In test we use transactions that are rolled back after each test. You can look at this - https://github.com/letsdrink/ouzo/blob/master/src/Ouzo/Core/Tests/DbTransactionalTestCase.php (this is our framework) as you can see there are override method setUp and tearDown which start and roll-back transactions after each test. You should write an integration test.

    How does this work?

    You can look for concrete 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);
    }
    

    Work-flow:

    1. Run method setUp which is starting transaction.
    2. Create object Product and inserting to the database.
    3. Fetch concrete object.
    4. Assertion.
    5. Run method tearDown which roll-back database to previous state.

    And here is link to the docs.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 hexo+github部署博客
  • ¥15 求螺旋焊缝的图像处理
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥15 网络通信安全解决方案
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面
  • ¥15 itunes恢复数据最后一步发生错误
  • ¥15 关于#windows#的问题:2024年5月15日的win11更新后资源管理器没有地址栏了顶部的地址栏和文件搜索都消失了
  • ¥100 H5网页如何调用微信扫一扫功能?