如何在PHP单元测试中避免竞态条件

3

让我们从明确这是一种竞态条件入手:

测试用例失败 ❌

phpunit --filter testMethod testlass path/to/testFile.php
PHPUnit 5.7.26 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

You should really fix these slow tests (>500ms)...
 1. 6441ms to run testClass::testMethod


Time: 6.49 seconds, Memory: 22.00MB

There was 1 failure:

1) ≈
Unable to find row in database table [orders] that matched attributes 
[{"collect_cash":104,"id":1728,"final_total":100}].
Failed asserting that 0 is greater than 0.

project/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php:24
path/to/testFile.php:78

FAILURES!
Tests: 1, Assertions: 2, Failures: 1.

这里有一个相同的测试,而且成功通过了,没有任何代码更改:

成功的测试用例 ✅

$ phpunit --filter method class path/to/testFile.php
PHPUnit 5.7.26 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

You should really fix these slow tests (>500ms)...
 1. 1631ms to run testClass::testMethod

Time: 1.68 seconds, Memory: 22.00MB

故障发生的位置

故障发生在检查数据库记录的位置:

    $this->shopperPut("/some/api/call")
        ->seeApiSuccess();

    $this->seeInDatabase('orders', [
        'collect_cash'  => $order->final_total + $chargeFare,
        'id'            => $order->id,
        'final_total'   => $order->final_total,

/some/api/call内,我们执行以下操作

    .. some logic

    $order->save();

    .. more logic

    return response()->success(compact('order'));

我尝试过的方法

我尝试过使用sleep命令.. 但这是一种hacky的方法,会使测试变慢,并且最重要的是并不总是有效。

还有什么其他的办法吗?

注:这个问题与许多开发人员使用相同的数据库无关。这只是在我的本地主机上,事实上我正在使用一个专门用于单元测试的testDatabase。

1个回答

0

我已经成功运行了类似的测试,没有出现竞争条件的问题。

$response = $this->get('/some/api/call');

$response->assertSessionHas('order');

$this-assertDatabaseHas('orders', [
    'collect_cash'  => $order->final_total + $chargeFare,
    'id'            => $order->id,
    'final_total'   => $order->final_total,
]);

https://laravel.com/docs/5.5/database-testing#introduction


有趣.. 你能提供assertDatabaseHas的文档参考吗? - abbood
该死的,这只有在Laravel 5.5中才可用!我现在用的是5.3... 这是另一个升级的理由。 - abbood
2
但这并不是一个好的回答。如果你告诉我在使用assertDatabaseHas之前你有竞态条件,并且使用这种方法解决了你的问题,那么我会更加高兴。现在你只是告诉我:嘿,伙计,我没有竞态条件!好啊,那就太好了 :) - abbood
我认为你遇到了竞态条件,是因为请求的执行方式不当,而不是数据库断言的问题。类似于“即使请求尚未完成,也要发送此请求并检查数据库”。 - Lloople

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接