In this tutorial we will go through on how we can start writing PHPUnit feature test in Laravel.

Feature testing can be used to test the smallest working part of your application

Let's consider an Blog Application where you have Post Model, A Post has a title and a body. Let's write some feature test with TDD approach to test our Post Model functionality.

Before jumping on to writing tests, do consider generating a Model, Resourceful Controller and a migration file, and also Setup your database seed if you are looking to write the feature test following this tutorial. Following tutorials will come handy.


Let's start with our first Feature test in Laravel.

As we are about to start writing our first test, realize that we don't want to test with our local database, since it might be populated with ton's of user's and other data.

For the tests we should be able to whip up the exact data we need for the particular test to work.

For this we will make changes to the test configuration for database that will be used for out phpunit testing. Go to phpunit.xml which is located in the root folder of your project and make sure to add following properties in the environment variables at the end of the file.

<env name="APP_ENV" value="testing"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory"/>

:memory: value of DB_DATABASE tells sqlite that we are not using actual file , just do it all in memory.

Alright, we are now set to write the first Feature test.

Open your IDE, and navigate to folder tests > Feature.

Notice, that there is already a ExampleTest.php available in the folder. This is where we are looking to create a new test.

To create a new Feature test, Navigate to terminal / command line and execute the following command.

php artisan make:test PostsTest

This will generate a new test in your tests > Feature folder named PostsTest.php with following code.

<?php

namespace Tests\Feature;

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

class PostsTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        $this->assertTrue(true);
    }
}

Alright, Let's modify this test and work around it in TDD approach.

Modify your PostsTest as per the following code.

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\TestCase;

class PostsTest extends TestCase
{
    use DatabaseMigrations;
    /**
     * A basic test example.
     *
     * @return void
     */

    /** @test  */
    public function a_user_can_browse_posts()
    {
        $response = $this->get('/posts');

        $response->assertStatus(200);
    }
}

We are using DatabaseMigrations, this will make sure to run the database migrations every time you run the test. Then once the test is completed it will roll it back. And remember the database migrations will happen in the memory, as we have defined in the phpunit.xml file.

We have renamed our function to a_user_can_browse_posts, also notice the comment /** @test */ on the top of the function. This is important for phpunit to recognize your test while running.

Go to your terminal and run the test by executing the following commmand.

vendor/bin/phpunit

The test will fail since, with following message.

1) Tests\Feature\PostsTest::a_user_can_browse_posts
Expected status code 200 but received 404.
Failed asserting that false is true.

This was expected, since we don't yet have a route in our web.php file that points to /posts url

Let's add that, Go to your web.php file and add the following route.

Route::get('/posts', 'PostsController@index');

Run the test again, and it should give you green.

 

Alright, we are moving great. Let's further modify this test, because currently it only tells us that the /posts page is working. We need to make sure that we see some posts in the /posts page.

Open your Post resource controller PostController.php, and modify the index methods to fetch the posts and then pass it on to the view.

public function index()
{
    $posts = Post::latest()->get();
    return view('posts.index',compact('posts'));
}

We now need to create a new view file index.blade.php under resources > views > posts

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                <div class="card-header">Posts</div>
                    <div class="card-body">
                       @foreach($posts as $post)
                           {{$post->title}}<br/>
                           {{$post->body}}
                            <hr/>
                        @endforeach
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

Alright, Let's modify our test to assert that we do see the post in /posts page.

/** @test  */
public function a_user_can_browse_posts()
{
    $post = factory('App\Post')->create();
    
    $response = $this->get('/posts');

    $response->assertSee($post->title);
}

Run the test again, and it should give you green. There you go, we have completed writing first Feature Test in Laravel.

Comments