基于 TDD 模式在 Laravel 项目中开发后端评论接口


在继续编写前端 Vue 评论组件之前,我们使用同样的测试驱动开发模式在 Laravel 项目中开发后端评论接口,正如学院君前面说的,除了框架和语法的不同,思路和模式是一模一样的。

编写测试用例

首先,在 Laravel 项目根目录下运行 make:test 命令创建一个测试类 CommentTest

-w718

然后打开这个测试类文件(位于 tests/Feature 目录下),编写简单的符合 BDD 风格的评论保存和获取接口测试用例代码如下:

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class CommentTest extends TestCase
{
    use RefreshDatabase;  // 测试用例在执行完毕后回滚数据库更新
    use WithFaker;  // 引入 Faker 伪造评论内容

    protected function setUp(): void
    {
        parent::setUp();
        $this->faker = $this->makeFaker('zh_CN');  // 本地化 Faker
    }

    /**
     * @test
     */
    public function submit_comment_add_then_display()
    {
      	// Given
        $content = $this->faker->sentence;
      	
        // When
        $response = $this->post('/comments', ['content' => $content]);
       
        // Then
        $response->assertStatus(200);

        $response = $this->get('/comments');
        $response->assertSeeText($content);
    }
}

我们先通过 Faker 伪造评论内容,调用后端保存评论接口,保存成功后,再调用后端评论列表接口,如果返回数据包含刚刚提交的评论,则意味着评论保存和获取功能可用。

现在通过 php artisan test tests/Feature/CommentTest.php 命令运行这个测试用例,肯定会失败,因为后端接口都没有实现:

-w916

所有相关的响应断言返回的都是 404 状态码。接下来我们需要编写业务代码。

路由和控制器

首先我们需要注册相应的后端接口路由:

use App\Http\Controllers\CommentController;
Route::group(['prefix' => '/comments'], function () {
    Route::get('/', [CommentController::class, 'all']);
    Route::post('/', [CommentController::class, 'store']);
});

以及对应的控制器代码:

<?php

namespace App\Http\Controllers;

use App\Models\Comment;
use Illuminate\Http\Request;

class CommentController extends Controller
{
    public function all()
    {
        return Comment::orderByDesc('created_at')->simplePaginate(10);
    }
    public function store(Request $request)
    {
        $data = $request->validate([
            'content' => 'required'
        ]);
        $comment = new Comment($data);
        return $comment->save();
    }
}

此时测试仍然不通过,因为模型类和数据库还不存在:

-w858

所以响应状态码是 500。

模型类和数据库准备

接下来我们创建模型类和数据库迁移文件:

php artisan make:model Comment -m

生成的模型类位于 app/Models/Comment.php,我们在这个模型类中设置批量赋值白名单和关联关系:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    use HasFactory;

    protected $fillable = ['content'];

    public function user()
    {
        $this->belongsTo(User::class);
    }
}

.env 中配置数据库连接信息(需要提前创建好数据库 component_test):

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=component_test
DB_USERNAME=root
DB_PASSWORD=root

编辑评论表对应的数据库迁移文件如下:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCommentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('user_id')->unsigned()->default(0);
            $table->string('content');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('comments');
    }
}

我们只设置了主键 ID、user_idcontent 以及创建/更新时间几个字段。然后运行 php artisan migrate 命令创建数据表:

-w714

让业务代码通过测试用例

此时再去运行 php artisan test 测试命令,测试通过:

-w838 表明我们的后端评论接口已经可以正常对外提供服务。

怎么样,你已经熟悉了 TDD 开发模式的精髓了吧:基于业务需求编写 BDD 风格的测试用例,然后编写能够通过这个测试用例的业务代码,接下来编写下一个测试用例。。。最终交付完整可用的功能代码。相信你会和我一样逐渐爱上这种让测试用例从红色变成绿色的感觉!

这里可以将业务代码编写和单元测试运行粒度变得更小,比如注册路由、编写控制器动作、实现模型类、数据表初始化等每个步骤进行一次测试,逐步迭代出通过测试用例的代码。测试驱动开发有两种模式,一种是先写测试用例,再写业务代码,一种是先写业务代码,再写测试用例,最终都要让业务代码通过每个测试用例,既然最终结果变绿,看你个人更喜欢哪种模式了。更多关于 Laravel 测试的功能和使用细节,请参考 Laravel 官方文档

下篇教程,学院君将给大家演示如何在前端 Vue 评论组件调用后端接口保存评论信息和渲染评论列表。


Vote Vote Cancel Collect Collect Cancel

<< 上一篇: 基于 TDD 模式编写 Vue 评论组件(上):数据绑定和列表渲染

>> 下一篇: 基于 TDD 模式编写 Vue 评论组件(中):父子组件之间的通信测试