Laravel测试不验证数据库约束

jac*_*414 8 phpunit laravel laravel-5

我有一个包含users表格的Laravel 5.3应用程序.该表上的一个字段是api_token,在数据库定义中设置为NOT NULL.如果我使用Postman并点击我的API端点来创建用户并且不包含该api_token字段,则会收到以下错误:SQLSTATE[HY000]: General error: 1364 Field 'api_token' doesn't have a default value.

我还没有添加代码来生成令牌,所以这正是我所期望的.但是,我有这个PHPUnit测试:

/** @test */
public function a_user_can_be_created()
{
    $this->user_data = [
        'first_name' => 'Jane',
        'last_name' => 'Smith',
        'email_address' => 'jsmith@mailinator.com',
        'phone' => '1234567890',
        'username' => 'jsmith',
        'password' => 'testing'
    ];

    $this->post('/api/users', $this->user_data, array(
                'Accept' => 'application/json'
            ))
         ->assertResponseStatus(201)
         ->seeJsonEquals(['status' => 'success'])
         ->seeInDatabase('users', $this->user_data);
}
Run Code Online (Sandbox Code Playgroud)

问题是测试通过了.当用户保存数据库时应该抛出异常,该测试如何成功?

我已经在不同时间点"死亡并倾倒"并确认在自动化测试运行时数据实际上已保存到数据库中.我也尝试使用相同的数据库进行Postman和自动测试(而不是单独的测试数据库) - 相同的结果.

Ris*_*ana 8

我尝试构建API的最小版本,并在最新的Laravel 5.3.22版本上创建类似的测试.我还使用MariaDB 10.1.13作为数据库.事实证明,由于空洞,测试失败了api_token.

1.用户迁移文件

这是我用于创建users表的迁移文件:

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

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('first_name');
            $table->string('last_name');
            $table->string('email_address')->unique();
            $table->string('phone');
            $table->string('username');
            $table->string('password');
            $table->string('api_token');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('users');
    }
}
Run Code Online (Sandbox Code Playgroud)

2.用户模型

这是我的app\User.php文件看起来像.非常小,我只更新$fillable属性以匹配我们的users表结构:

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    protected $fillable = [
        'first_name',
        'last_name',
        'email_address',
        'phone',
        'username',
        'password',
        'api_token',
    ];

    protected $hidden = [
        'password',
    ];
}
Run Code Online (Sandbox Code Playgroud)

3. API路由文件

我在routes/api.php文件上创建一个新的API路由来创建一个新用户.超级简单,无需任何验证:

Route::post('users', function (Request $request) {
    $data = $request->only([
        'first_name',
        'last_name',
        'email_address',
        'phone',
        'username',
        'password',
        'api_token',
    ]);

    if (is_string($data['password'])) {
        $data['password'] = bcrypt($data['password']);
    }

    $user = App\User::create($data);

    return response()->json([
        'status' => 'success',
    ], 201);
});
Run Code Online (Sandbox Code Playgroud)

4.创建用户API测试

最后这是我的测试文件,用于测试我们的创建用户API.

class ApiTest extends TestCase
{
    /** @test */
    public function a_user_can_be_created()
    {
        $user = [
            'first_name' => 'Jane',
            'last_name' => 'Smith',
            'email_address' => 'jsmith@mailinator.com',
            'phone' => '1234567890',
            'username' => 'jsmith',
        ];

        $this->json('POST', 'api/users', $user)
            ->assertResponseStatus(201)
            ->seeJsonEquals(['status' => 'success'])
            ->seeInDatabase('users', array_except($user, ['password']));
    }
}
Run Code Online (Sandbox Code Playgroud)

唯一的区别是我array_except()以前password从数据库测试中排除了列,因为我们在将值存储到数据库之前对其进行了散列.但是,这当然与您的问题无关.

当我在没有api_token设置的情况下运行测试时,测试按预期失败.API返回状态代码500,而我们预计它是201.

创建用户API失败了!

另外作为参考,当我将api_token列设置为NOT nullable时,然后强制创建一个空的新用户,api_token我收到的异常消息是这样的:

Connection.php第769行中的QueryException:

SQLSTATE [23000]:完整性约束违规:1048列'api_token'不能为空(SQL:插入用户...

希望这有助于您调试问题!


Sau*_*ogi 1

您应该为表api_token中的列定义一个默认值users,或者应该将其设置为nullable,您的用户表迁移将如下所示:

Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('api_token')->nullable();
    // Or you can set it to default value - 0
    // $table->string('api_token')->default('0');
    $table->timestamps();
});
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!