Laravel test does not confirm database limitation

I have a Laravel 5.3 application that includes a users table. One of the fields in this table is api_token , which in the database definition is NOT NULL. If I use Postman and delete the API endpoint to create the user and do not include api_token in the field, I get the following error: SQLSTATE[HY000]: General error: 1364 Field 'api_token' doesn't have a default value .

I haven't added the code to generate the token yet, so that's exactly what I would expect. However, I have this PHPUnit test:

 /** @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); } 

The problem is that the test passes. How can this test succeed when the database should throw an exception while saving the user?

I "died and dumped" at various points and confirmed that the data is actually stored in the database during automatic testing. I also tried to use the same database for Postman and automatic test (instead of a separate test database) - the same result.

+8
phpunit laravel laravel-5
source share
4 answers

I tried to create a minimal version of your API and create a similar test in the latest version of Laravel 5.3.22. I also used MariaDB 10.1.13 for the database. And it turned out that the test failed, as we expected, due to the empty api_token .

1. User migration file

Here is my migration file to create the users table:

 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'); } } 

2. User model

Here is my app\User.php . Quite minimally, I only update the $fillable property to match our users table structure:

 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', ]; } 

3. API routes the file

I am creating a new API route in the routes/api.php to create a new user. Super simple without any verification:

 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); }); 

4. Create a custom API test

And finally, here is my test file for testing our user 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'])); } } 

The only difference is that I used array_except() to exclude the password column from the database test, since we hadhed the value before storing it in the database. But of course, this is not related to your problem.

When I run the test without setting api_token , the test failed as expected. The API returns a status code of 500, and we expect it to be 201.

Error creating custom API!

Just like a link, when I set the api_token column as a NOT-null value, then force create a new user with an empty api_token , the error message I received looks like this:

QueryException on line 769 Connection.php:

SQLSTATE [23000]: violation of integrity constraint: 1048 The column "api_token" cannot be zero (SQL: insert into user ...

Hope this help helps you debug your problem!

+9
source share

I assume you are using mysql. In mysql there is a problem with NOT NULL . Everything goes like this. Although the NOT NULL field, you can leave it blank in mysql and the request will pass. NOT NULL in mysql means that you cannot have a NULL value in this field, and not that you cannot leave it empty. I assume you create a user like this

 User::create($request->all()) 

If you try to print the generated SQL query

 dd((new User($request->all())->toSql()) 

You will see that the generated request contains a '' value for the api_token field

I switched to posgres mainly because this problem.

If you want to solve this problem, you have several options. One of them is to leave the api_token field zero. The second is to manually fill in the model.

+2
source share

You must define a default value for the api_token column in the users table or it should be set to nullable , your migration table for users will look like this:

 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(); }); 

Hope this helps!

+1
source share

I think the problem is with Unit Test. Why don't you try the Laravel test using Eloquent? Something like that:

 public function a_user_can_be_created() { $user = new User; $user->first_name = 'Jane'; $user->last_name = 'Smith'; $user->email_address = 'jsmith@mailinator.com'; $user->phone = '1234567890'; $user->username = 'jsmith'; $user->password = 'testing'; $user->save(); return $user; } 

https://laravel.com/docs/5.3/testing

+1
source share

All Articles