【发布时间】:2021-11-08 00:52:18
【问题描述】:
我在我的项目中使用 Laravel,并且我是单元/功能测试的新手,所以我想知道在编写测试时处理更复杂的功能用例的最佳方法是什么?
我们以这个测试为例:
// tests/Feature/UserConnectionsTest.php
public function testSucceedIfConnectAuthorised()
{
$connection = factory(Connection::class)->make([
'sender_id' => 1,
'receiver_id' => 2,
'accepted' => false,
'connection_id' => 5,
]);
$user = factory(User::class)->make([
'id' => 1,
]);
$response = $this->actingAs($user)->post(
'/app/connection-request/accept',
[
'accept' => true,
'request_id' => $connection->id,
]
);
$response->assertLocation('/')->assertStatus(200);
}
所以我们遇到了这种情况,我们在两个用户之间有一些连接系统。由其中一位用户创建的数据库中有一个Connection 条目。现在要使其成功连接,第二个用户必须批准它。问题在于UserController 通过connectionRequest 接受这个:
// app/Http/Controllers/Frontend/UserController.php
public function connectionRequest(Request $request)
{
// we check if the user isn't trying to accept the connection
// that he initiated himself
$connection = $this->repository->GetConnectionById($request->get('request_id'));
$receiver_id = $connection->receiver_id;
$current_user_id = auth()->user()->id;
if ($receiver_id !== $current_user_id) {
abort(403);
}
[...]
}
// app/Http/Repositories/Frontend/UserRepository.php
public function GetConnectionById($id)
{
return Connection::where('id', $id)->first();
}
所以我们在测试函数中得到了这个假的(工厂创建的)连接,然后我们不幸的是使用它的假 id 在真实数据库中的真实连接中运行检查,这不是我们想要的:(
研究我发现了创建接口的想法,这样我们就可以根据我们是否正在测试提供不同的方法体。就像这里的 GetConnectionById() 一样,可以很容易地伪造测试用例的答案。这看起来不错,但是:
- 对于一个人来说,这看起来像是一种开销,除了编写测试之外,我还必须使“真实”代码本身变得更加复杂,以便进行测试。
- 第二件事,我阅读了 Laravel 文档中关于测试的所有内容,并且没有一个地方提到使用接口,所以我也想知道这是否是解决这个问题的唯一方法和最佳方法问题。
【问题讨论】:
-
针对真实数据库运行它的代码在哪里?您可以嘲笑它,但从您的问题中我无法真正弄清楚那在哪里。
-
这是最后一个代码示例 -
UserRepository。这是应用程序使用的真实代码,这就是我在真实数据库上工作的代码。第一个代码示例 -UserConnectionsTest.php是工厂制作不在真实数据库中的假连接的地方。 -
我倾向于建议您模拟存储库并对功能设置期望以检索和批准连接(如果有),这样您就不需要更改数据库。或者,您可以使用测试数据库或
DatabaseTransactions特征回滚任何数据库更改 -
在这种情况下你使用 make() make 不会向数据库添加任何内容,这是为什么呢?
-
在测试时,您根本不应该针对真实数据库进行测试,而是针对您环境中的测试数据库进行测试,并且许多人更喜欢使用将数据库设置为内存中的 Sqlite 进行测试。
标签: laravel testing laravel-5 phpunit