Better Integration Testing in Laravel 5.1: Powerful Integration Tests in A Few Lines

Posted on June 15, 2015 | By Matt Stauffer


Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

Whether or not you've written integration tests in Laravel before, you'll be pleased to hear that integration testing is more powerful, easier to use, and easier to learn in Laravel 5.1.

Note: If you do a lot of testing, it's likely you already have Faker and Mockery installed on every site you run, but you just got saved a step: they're now installed by default.

Integration Tests?

For a quick refresher, integration tests are those which test your entire system as an integrated application, as compared against unit tests, which test each system of your application separately.

Usually integration tests pass in input to your application (often just an instruction like "visit this page") and check the output (often "I should see this text somewhere on the page"), with no concern of how that input was converted to that output. Integration tests see the actual processes running your application as a black box. Don't know, don't care.

Integrated package integrated

Jeffrey Way's fantastic Integrated package has given integration tests in Laravel superpowers for a while now, and it's now a part of the Laravel core.

This means that any tests extending TestCase provide a simple, fluent interface for you to operate what amounts to almost a fake web browser that can check your output. If you've ever written Selenium-based tests, think that but simpler and easier to set up.

I'll show a few examples here, but note that the full documentation is available at the docs.

Simple tests with visit() and see()

Check this out:

<?php
...
class HomePageTest extends TestCase
{
    public function test_home_page_says_wowee()
    {
        $this->visit('/')
            ->see('Wowee');
    }
}

In two lines of code, we just tested that a user who visits the home page of the application sees the phrase "Wowee" somewhere on the site. Two lines of code. If you have any imagination, you can see how far we can take this, with almost no work, to ensure that the front end of our application functions properly, not just its guts.

Check the page with seePageIs()

    public function test_forwarder_forwards_the_page()
    {
        $this->visit('/forwarder')
            ->seePageIs('forwarded-to');
    }

Check links with click()

    public function test_cta_link_functions()
    {
        $this->visit('/sales-page')
            ->click('Try it now!')
            ->see('Sign up for trial')
            ->onPage('trial-signup');
    }

Fill out forms with type(), select(), check(), attach(), and press()

There are many more interactions you can script with the new functionality.

For example, you can fill out a form and submit it:

    public function test_it_can_subscribe_to_newsletter()
    {
        $this->visit('/newsletter')
            ->type('me@me.com', '#newsletter-email')
            ->press('Sign Up')
            ->see('Thanks for signing up!')
            ->onPage('newsletter/thanks');
    }

Note that press() can either be passed the value of the button (press("Sign Up")) or the name (press("sign-up-button"))

You can also fill out other fields:

    public function test_signups_can_complete()
    {
        $this->visit('/signup')
            ->type('Matt Stauffer', 'name')
            ->check('overTwentyOne')
            ->select('Florida', 'state')
            ->attach('../uploads/test.jpg', 'profilePicture')
            ->press('Sign Up')
            ->seePageIs('/signup/thanks');
    }

Submit a form all at once with submitForm()

    public function test_login_form()
    {
        $this->visit('/login')
            ->submitForm('Log In', ['email' => 'me@me.com', 'password' => 'secret'])
            ->see('Welcome!')
            ->onPage('dashboard');
    }

Verify a record exists in the database with seeInDatabase()

    public function test_saves_newsletter_signups()
    {
        $this->visit('/newsletter-signup')
            ->type('me@me.com')
            ->press('Sign up')
            ->seeInDatabase('signups', ['email' => 'me@me.com']);
    }

Super power auto-testing

Cool trick: you can tell Elixir to run your tests every time you modify a file by adding the following code to your gulp file: mix.phpUnit(). Now, just run gulp tdd from the command line and it will re-run PHPUnit every time you change any of your files and notify you of the results.

Thanks to Jeffrey Way for pointing this out—I had no idea it existed and now I'm in love with it.

Conclude

As you can see, bringing in Integrated has laid the foundation for simple and powerful integration tests with almost no work. I have to make this clear: I've written integration tests before and it's never been this easy to get started.

We're not done yet—check back later this week to learn more about all the amazing things you can do with integration testing in Laravel 5.1.


Comments? I'm @stauffermatt on Twitter


Tags: laravel  •  laravel 5.1  •  testing  •  integration testing