In my previous article, I had explained why should we use Laravel factories. You can check the article at Factories To Speed Up Test-Driven Development In Laravel.
In this article let's see how we can use Factory states to write fluent test cases.
First, let's see how does our test cases look like without any factory states. Basically, we are writing a test to check that the user cannot view any unpublished blog posts.
/**
* @test
*/
public function user_cannot_view_unpublished_post()
{
$post = Post::factory()->create([
'published_at' => null
]);
$resource = $this->get("/posts/" . $post->slug);
$resource->assertStatus(404);
}
public function definition() {
$title = $this->faker->title;
return [
'title' => $title,
'slug' => Str::slug($title),
'summary' => $this->faker->paragraph,
'body' => $this->faker->paragraph,
'author_id' => function () {
return User::factory()->create()->id;
},
'published_at' => Carbon::parse('-1 week'),
];
}
/**
* @test
*/
public function user_cannot_view_unpublished_post()
{
$post = factory(Post::class)->create([
'published_at' => null
]);
$resource = $this->get("/posts/" . $post->slug);
$resource->assertStatus(404);
}
$factory->define(Post::class, function (Faker $faker) {
$title = $faker->title;
return [
'title' => $title,
'slug' => Str::slug($title),
'summary' => $faker->paragraph,
'body' => $faker->paragraph,
'author_id' => function () {
return factory(User::class)->create()->id;
},
];
});
Basically, there is no problem with the above approach. Since we can write more cleaner we can use this approach.
From the above code snippet, we can write the code
/**
* @test
*/
public function user_cannot_view_unpublished_post()
{
$post = Post::factory()->states(['unpublished'])->create();
$resource = $this->get("/posts/" . $post->slug);
$resource->assertStatus(404);
}
use App\Post;
use App\User;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Faker\Generator as Faker;
public function definition(){
$title = $this->faker->title;
return [
'title' => $title,
'slug' => Str::slug($title),
'summary' => $this->faker->paragraph,
'body' => $this->faker->paragraph,
'author_id' => function () {
return User::factory()->create()->id;
},
'published_at' => Carbon::parse('-1 week'),
];
}
public function unpublished()
{
return $this->state(function (array $attributes) {
return [
'published_at' => null
];
});
}
public function published()
{
return $this->state(function (array $attributes) {
return [
'published_at' => Carbon::parse('-1 week')
];
});
}
$post = factory(Post::class)->create([
'published_at' => null
]);
$post = factory(Post::class)->states(['unpublished'])->create();
Now your test case will look like the following very lean, clean & fluent
/**
* @test
*/
public function user_cannot_view_unpublished_post()
{
$post = factory(Post::class)->states(['unpublished'])->create();
$resource = $this->get("/posts/" . $post->slug);
$resource->assertStatus(404);
}
use App\Post;
use App\User;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Faker\Generator as Faker;
$factory->define(Post::class, function (Faker $faker) {
return [
'title' => $title,
'slug' => Str::slug($title),
'summary' => $faker->paragraph,
'body' => $faker->paragraph,
'author_id' => function () {
return factory(User::class)->create()->id;
},
];
});
$factory->state(Post::class, 'unpublished', function (Faker $faker) {
return [
'published_at' => null
];
});
/** Similarly you can have published state too */
$factory->state(Post::class, 'published', function (Faker $faker) {
return [
'published_at' => Carbon::parse('-1 week')
];
});
I hope this article helped you. Please share it with your friends.
Create Gmail App Password For SMTP Mails
Securely SSH Your Server & Push Files With FileZilla
Debugging Laravel Queue Email Issues
Lazy Load Images In Chrome With This Simple Trick
Supervisor For Laravel Queue Scheduling
Increase Session Timeout In Laravel
Composer Install v/s Composer Update
PHP file_put_contents failed to open stream: Permission denied
Make Laravel Controllers Slim By Skimming Form Validation Request
Simple Way To Create Resourceful API Controller In Laravel
Sass or SCSS @function vs @mixin
Google reCAPTCHA Integration In PHP Laravel Forms
Laravel 7.x Multiple Database Connections, Migrations, Relationships & Querying
Unable to prepare route [{fallbackPlaceholder}] for serialization. Uses Closure In Laravel