Laravel 功能/单元测试

时间:2021-06-23 14:23:40

标签: laravel laravel-testing

由于我还是 Laravel 的初学者,我偶然发现了一个有趣的测试问题,需要第二意见。

我编写了模型、控制器、视图、工厂、播种机,然后是(功能)测试。测试确实涵盖了很多(不会说全部),但我刚刚发现了一个测试没有发现的问题,尽管它应该。测试主要是通过调用 HTTP 端点来完成的,所以理论上它应该像用户一样显示、添加、编辑和删除数据。工厂正在确保输入的数据与用户输入的数据大致相同(请让我们在本次演讲中忽略欺诈用户,他们可以更改 HTTP POST 请求)。

所以问题是模型的属性接受 truefalse,工厂只为该属性生成这两个值,但在控制器中编辑时我错误地设置了如果值为 false 或不存在,它将值设置为 null。奇怪的是,尽管我进行了大量测试,但之前从未出现过这个问题,只有在我手动尝试更新模型时才会出现。

那么,我的问题:

  • 为什么测试没有发现这个问题,尽管在某些情况下我的编辑调用确实为该属性发送了 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]:违反完整性约束:1048 列“invoice_details”不能为空(SQL:更新 clients set invoice_details = ?, clients.updated_at = 2021-06-23 13:14:15 其中 id = 1)

1 个答案:

答案 0 :(得分:0)

我正在用手机写作,所以请记住这一点。

测试的想法是测试一切,你写了不确定是写很多测试还是做。简短的回答是<ul id="pictures"> <li> <a href="/" class="hoverelement"> <img src="1.jpg" height="250" width="250"> <div class="image-text"><p>TEXT</p></div> </a> </li> </ul>,做吧,因为这就是想法,测试所有可能的结果。

有些端点实际上是 2 次测试,有些是 30 次...您没有发现这个 yes/true (false) 问题,因为您没有测试端点得到错误的值,在本例中为 null 或任何会产生该值的值。

因此您必须发送错误的属性(值)并期望返回错误,当发生这种情况时,您的测试通过。使用null。在文档中查找它,因为您可以传递像 $response->assertSessionHasError('invoice_details') 这样的数组。

如果您有更多问题,请更新您的问题或使用您的代码创建一个新问题。