DEV Community

Cover image for Notes on Starting Functional Testing in Laravel
Kenta Takeuchi
Kenta Takeuchi

Posted on • Originally published at bmf-tech.com

Notes on Starting Functional Testing in Laravel

This article was originally published on bmf-tech.com.

Overview

This post introduces how to start functional testing in Laravel and some basic usage. It is limited to an introductory level, so more practical content is not covered. ※ This is just a memo-level content, like a source for a lightning talk.

Target Audience

This is for people who have never written tests before.

Even if you have never written tests, as long as you understand the application's specifications, functional testing should be relatively easy for anyone to understand what to write.

Especially in Laravel, there are plenty of convenient APIs and tools available for functional testing, so even if you're not familiar with testing, it should be easy to get started.

Environment

  • Docker
  • Laravel 5.7
  • MySQL

Preparation

I have roughly prepared the environment.

github - bmf-san/laravel-test-handson

By following the commands in the README, you can set up a Laravel environment on Docker.

As preparation for an environment where tests can be executed, I prepared a test db and modified phpunit.xml and config/database.php on the application side.

To use the convenient API for functional testing, I have introduced github - laravel/browser-kit-testing.

This was originally included in the Laravel core until version 5.3, but it seems to have become a separate package around version 5.4.

Since I hadn't caught up with Laravel since version 5.3, I realized this after touching version 5.7...

It's not a big deal, but I can no longer say "You can start immediately without introducing a separate package!"

Starting the Test

The actual code is placed here, so I'll introduce a part of it.

github - laravel/browser-kit-testing

Suppose there is a screen to create a new article.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
          <form method="POST" action="/post/store">
              @csrf

              <div class="form-group row">
                  <label for="name" class="col-md-4 col-form-label text-md-right">Title</label>

                  <div class="col-md-6">
                      <input id="title" type="text" class="form-control{{ $errors->has('title') ? ' is-invalid' : '' }}" name="title" value="{{ old('title') }}" required autofocus>

                      @if ($errors->has('title'))
                          <span class="invalid-feedback" role="alert">
                              <strong>{{ $errors->first('title') }}</strong>
                          </span>
                      @endif
                  </div>
              </div>

              <div class="form-group row">
                  <label for="name" class="col-md-4 col-form-label text-md-right">Body</label>

                  <div class="col-md-6">
                      <textarea class="form-control{{ $errors->has('body') ? ' is-invalid' : '' }}" id="body" name="body" required>{{ old('body') }}</textarea>
                      @if ($errors->has('body'))
                          <span class="invalid-feedback" role="alert">
                              <strong>{{ $errors->first('body') }}</strong>
                          </span>
                      @endif
                  </div>
              </div>

              <div class="form-group row mb-0">
                  <div class="col-md-6 offset-md-4">
                      <button type="submit" class="btn btn-primary">
                        Submit
                      </button>
                  </div>
              </div>
          </form>
        </div>
    </div>
</div>
@endsection
Enter fullscreen mode Exit fullscreen mode

The routing looks like this.

Route::get('post/create', 'PostController@create');
Route::post('post/store', 'PostController@store');
Enter fullscreen mode Exit fullscreen mode

Then you can write intuitive functional tests like this.

<?php

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\User;
use App\Post;

class PostTest extends TestCase
{
    use DatabaseMigrations, DatabaseTransactions;

    public function testCreatePost()
    {
      $user = factory(User::class)->create();

      $this->actingAs($user);
      $this->visit("/post/create");
      $this->type("title", "title");
      $this->type("body", "body");
      $this->press("Submit");
      $this->seePageIs("/post");
    }
}
Enter fullscreen mode Exit fullscreen mode

Impressions

This is just a rough memo for a lightning talk.

References

Top comments (0)