Laravel Feature/Unit 测试
Laravel Feature/Unit Testing
由于我在 Laravel 方面还是个初学者,所以我偶然发现了一个有趣的测试问题,需要第二个意见。
我编写了模型、控制器、视图、工厂、播种器,然后是(功能)测试。测试确实涵盖了很多(不会说全部),但我只是发现了一个测试没有发现的问题,尽管它应该。测试主要通过调用 HTTP 端点来完成,因此理论上它应该像用户一样显示、添加、编辑和删除数据。工厂正在确保输入的数据与用户输入的数据大致相同(请让我们在本次演讲中排除欺诈用户,这可以更改 HTTP POST 请求)。
所以问题是模型的属性接受 true
或 false
,工厂只为该属性生成这两个值,但在编辑时在控制器中我错误地设置了值是否为 false目前,它将值设置为 null
。 St运行gely,尽管我运行进行了很多测试,这个问题以前从未出现过,只有在我手动尝试更新模型时才会出现。
所以,我的问题:
- 为什么测试没有发现这个问题,尽管在某些情况下我的编辑调用确实为该属性发送了
false
?
- 您为代码编写的测试有多详细?您是否使用有效和无效数据来测试可能的结果,进行大量测试?因为测试所有可能的组合会使测试数量巨大。
一些代码,因为我知道你们中的一些人会问(注意我只会添加相关部分,而不是所有内容):
迁移:
class CreateClientsTable extends Migration
{
public function up()
{
Schema::create('clients', function (Blueprint $table) {
$table->id();
...
$table->boolean('invoice_details')->default(false);
...
});
}
public function down()
{
Schema::dropIfExists('clients');
}
}
型号:
class Client extends Model
{
use HasFactory;
protected $fillable = [
...
'invoice_details',
...
];
...
protected static function newFactory(): Factory
{
return ClientFactory::new();
}
}
控制器:
class ClientController extends Controller
{
...
public function edit(int $id): View
{
$data = Client::findOrFail($id);
return view('client::edit', compact('data'));
}
public function update(UpdateClientRequest $request, int $id)
{
$client = Client::findOrFail($id);
$response = $client->update([
...
'invoice_details' => $request->invoice_details ?? null, // NOTE THE NULL, THIS TRIGGERED THE ERROR
...
]);
...
return CustomResponse::resource($request, 'update', $response, route('client.index'), Client::findOrFail($id));
}
}
工厂:
class ClientFactory extends Factory
{
protected $model = Client::class;
public function definition(): array
{
$details = [
...
'invoice_details' => $this->faker->randomElement([true, false]),
];
if ($details['invoice_details']) {
...
}
return $details;
}
}
播种机:
class ClientsSeeder extends Seeder
{
public function run()
{
$client = Client::factory()->create();
}
}
错误:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'invoice_details' cannot be null (SQL: update clients
set invoice_details
= ?, clients
.updated_at
= 2021-06-23 13:14:15 where id
= 1)
我正在用手机写作,所以请记住这一点。
测试的想法是测试一切,你写道不确定是否要写很多测试或做。简短的回答是 yes
,去做吧,因为这就是想法,测试所有可能的结果。
有的端点真的是2个测试,有的是30...你没抓到这个true
/false
(null
)问题,因为你没有测试端点得到错误的值,null
在这种情况下或任何会创建该值的值。
所以你必须发送一个错误的属性(值)并期待一个错误返回,当这种情况发生时,你的测试通过。使用 $response->assertSessionHasError('invoice_details')
。在文档中查找它,因为您可以传递像 ['attribute_name' => 'expected error message']
.
这样的数组
如果您有更多问题,请更新您的问题或使用您的代码创建一个新问题。
由于我在 Laravel 方面还是个初学者,所以我偶然发现了一个有趣的测试问题,需要第二个意见。
我编写了模型、控制器、视图、工厂、播种器,然后是(功能)测试。测试确实涵盖了很多(不会说全部),但我只是发现了一个测试没有发现的问题,尽管它应该。测试主要通过调用 HTTP 端点来完成,因此理论上它应该像用户一样显示、添加、编辑和删除数据。工厂正在确保输入的数据与用户输入的数据大致相同(请让我们在本次演讲中排除欺诈用户,这可以更改 HTTP POST 请求)。
所以问题是模型的属性接受 true
或 false
,工厂只为该属性生成这两个值,但在编辑时在控制器中我错误地设置了值是否为 false目前,它将值设置为 null
。 St运行gely,尽管我运行进行了很多测试,这个问题以前从未出现过,只有在我手动尝试更新模型时才会出现。
所以,我的问题:
- 为什么测试没有发现这个问题,尽管在某些情况下我的编辑调用确实为该属性发送了
false
? - 您为代码编写的测试有多详细?您是否使用有效和无效数据来测试可能的结果,进行大量测试?因为测试所有可能的组合会使测试数量巨大。
一些代码,因为我知道你们中的一些人会问(注意我只会添加相关部分,而不是所有内容):
迁移:
class CreateClientsTable extends Migration
{
public function up()
{
Schema::create('clients', function (Blueprint $table) {
$table->id();
...
$table->boolean('invoice_details')->default(false);
...
});
}
public function down()
{
Schema::dropIfExists('clients');
}
}
型号:
class Client extends Model
{
use HasFactory;
protected $fillable = [
...
'invoice_details',
...
];
...
protected static function newFactory(): Factory
{
return ClientFactory::new();
}
}
控制器:
class ClientController extends Controller
{
...
public function edit(int $id): View
{
$data = Client::findOrFail($id);
return view('client::edit', compact('data'));
}
public function update(UpdateClientRequest $request, int $id)
{
$client = Client::findOrFail($id);
$response = $client->update([
...
'invoice_details' => $request->invoice_details ?? null, // NOTE THE NULL, THIS TRIGGERED THE ERROR
...
]);
...
return CustomResponse::resource($request, 'update', $response, route('client.index'), Client::findOrFail($id));
}
}
工厂:
class ClientFactory extends Factory
{
protected $model = Client::class;
public function definition(): array
{
$details = [
...
'invoice_details' => $this->faker->randomElement([true, false]),
];
if ($details['invoice_details']) {
...
}
return $details;
}
}
播种机:
class ClientsSeeder extends Seeder
{
public function run()
{
$client = Client::factory()->create();
}
}
错误:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'invoice_details' cannot be null (SQL: update
clients
setinvoice_details
= ?,clients
.updated_at
= 2021-06-23 13:14:15 whereid
= 1)
我正在用手机写作,所以请记住这一点。
测试的想法是测试一切,你写道不确定是否要写很多测试或做。简短的回答是 yes
,去做吧,因为这就是想法,测试所有可能的结果。
有的端点真的是2个测试,有的是30...你没抓到这个true
/false
(null
)问题,因为你没有测试端点得到错误的值,null
在这种情况下或任何会创建该值的值。
所以你必须发送一个错误的属性(值)并期待一个错误返回,当这种情况发生时,你的测试通过。使用 $response->assertSessionHasError('invoice_details')
。在文档中查找它,因为您可以传递像 ['attribute_name' => 'expected error message']
.
如果您有更多问题,请更新您的问题或使用您的代码创建一个新问题。