Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

JeffreyWay's avatar

Easier Integration Testing with PHPUnit

Hey, all -

Thought I'd show you this thing I'm working on over the weekend. It gives you a much easier way to write integration tests in PHPUnit. While tools like Codeception and Behat exist (and are great), they can sometimes be confusing to setup. But, particularly for Laravel work, this method requires no thinking and is pretty intuitive, in my mind. It's also super super fast.

It's not yet available to use, but will be in a few days. I already have it working locally, so just need to dog food it for a while. But, here's the type of things you'll be able to do:

<?php

class ExampleTest extends IntegrationTest
{

    /** test */
    function it_verifies_that_pages_load_properly()
    {
        $this->visit('/');
    }

    /** test */
    function it_follows_links()
    {
        $this->visit('/page-1')
             ->click('Follow Me')
             ->andSee('You are on Page 2')
             ->onPage('/page-2');
    }

    /** @test */
    function it_submits_forms()
    {
        $this->visit('page-with-form')
             ->submitForm('Submit', ['title' => 'Foo Title'])
             ->andSee('You entered Foo Title')
             ->onPage('/page-with-form-results');

        // Another way to write it.
        $this->visit('page-with-form')
             ->type('Foo Title', '#title')
             ->press('Submit')
             ->see('You Entered Foo Title');
    }

    /** @test */
    function it_verifies_information_in_the_database()
    {
        $this->visit('database-test')
             ->type('Testing', 'name')
             ->press('Save to Database')
             ->verifyInDatabase('things', ['name' => 'Testing']);
    }

}

If I can get everything clean enough, we might even be able to get this into Laravel core. We'll see...

0 likes
37 replies
vincej's avatar

"requires no thinking" .. I like that.

Seriously, as an independent, I often find the labour of setting up tests just is often not worth it, when I can user test quickly.

theUnforgiven's avatar

@JeffreyWay this is cool, I really need to get into testing but it's kinda scares me. What would you say is the best way to start learning this stuff? I know you have some casts on it but really starting with the basics and understanding the patterns and procedures.

RemiC's avatar

Neat! I'm really curious to see how you implemented this. Seems you're using annotation to detect which method is an integration test, right?

puzbie's avatar

@Istables, try the Larabook tutorial, focusing on the TDD components. Also get Jeff's TDD book. And try other TDD courses on Laracasts, and don't mind that you don't really understand them. Keep going over them and eventually you will get it.

Once you get it, you will still have the "Is it worth it?" debate, but you will at least now be able to have that debate from a position of knowledge.

1 like
JeffreyWay's avatar

@Remic - Nope. The @test annotation is just a way to tell PHPUnit that the current method should be tested.

@lstables - There are dozens and dozens of testing videos here. Just start watching them. It's a slow process. Begin by testing little classes that have clear returns that can be tested. Then work up from there.

RemiC's avatar

Ah ok, good to know, i assumed you had to prepend 'test' to each test method name. Still have to dig deeper into phpunit i guess :)

theUnforgiven's avatar

@puzbie I have done these tuts a couple of times, but one I do question the "is it worth it" and two "why" do it, but I want to do it as it does seem like a good thing to do, specially working with other devs, just wanted to know how to get started in terms of what do you call each method etc.

@JeffreyWay Great, I will do that by going from the start again and just returning some text and go from there like you say. Is it really worth and what benefits would you see from this, I see working with other devs as the plus side. Are there any downsides to it?

dbbk's avatar

So would this make Codeception irrelevant for Laravel if you could do unit and integration testing both with PHPUnit? Are there any downsides?

JeffreyWay's avatar

@dbbk - It's mostly an alternative. I like Codeception. But it's a full test framework. Sometimes, you don't need that.

@lstables - The "is it really worth it" question has been answered a long time ago. Any open source project worth its salt these days has a set of tests. Otherwise, reviewing and merging pull requests would be a nightmare. And then, for regular apps, well personally I'd be terrified to push code to Laracasts if I didn't have some level of assurance that I didn't just blow everything up. :)

theUnforgiven's avatar

@JeffreyWay Ok, just something I've never really "had" to do it's always been me, but as time is developing on I'm working with bigger companies and with other devs, so I guess I really need to start doing these tests. Thanks for your input much appreciated.

Ratty's avatar

Integration testing is always much more of a pain than unit testing so anything that makes it less of a chore is always welcome !

Ratty's avatar

@lstables - The downside, if you can call it that, to Unit testing is when you have to change some low level design in your code (usually due to a clients specification change) as changing the code to fit the new design will obviously mean that all the tests on that code start to fail and you will have to fix them. However, even this can be good since it will highlight areas of code that have been affected by the change that you may not have thought of or overlooked.

erozas's avatar

Like many of you, I'm afraid of testing but I think I'm going to give it a try soon. I bet that Laracasts lessons on the matter are pretty good. I have a sense that testing isn't exclusively about, well "testing" your app but also about enforcing you to think and code better. At least that's what I get seeing some tests being done.

deadlockgB's avatar

the methods sound like they are fom "Buffalo Bill" from "The Silence of the Lambs". I like the movie and therefore will try your package @JeffreyWay

bbloom's avatar

@JeffreyWay Tremendous effort and timing -- working late on Friday on this very thing when I saw your tweet. Thank you for letting us know about your new package whilst in development..

The obstacle I came across, and thought I had solved (wrong!), is providing a _token without disturbing the token middleware. I would prefer to avoid adding conditionals in my Kernel file for the "testing" env.

Your "->onPage()" usually specifies the route someone sees at the end of the request cycle, given the correct $formData? Given incorrect $formData on purpose, as part of a test case, onPage() can also specify the page someone should see when incorrect $formData is used (looks like it!)?

May I suggest that you do not PR this wonderful package, and in general your Laravel packages, for inclusion into the Laravel core. Akin to form packages are now excluded from the core, test packages should be excluded from the core. Maintain your innovations as separate packages, in part to keep the Laravel core lean; and, in part, to keep your packages' development vibrant.

My use of the word "vibrant" is a way to mask over a negative scenario. Let's say your Integration_Test package is accepted into Laravel's core. Now, you'll have to submit a PR for any changes. If you have particular innovation that is rejected, but you feel strongly about its inclusion, then you'll have to fork your own package to make that inclusion.

Along with TestDummy, I suspect you are ramping into a new testing framework. Keep it going!

Again, thank you for your tremendous effort in focusing your talents on this important area of Laravel testing; and, for disclosing your efforts ahead of its beta release.

I bought your testing book (the actual book with real pages, not merely the ebook) and am looking forward to your follow-up testing book.

theUnforgiven's avatar

Based on my contributions/questions earlier today, I've decided I'm going to do some Unit Testing, but come across my first stumbling block!

When I run phpunit from the terminal I get the following error:

lee$ phpunit
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.

Configuration read from /Users/lee/code/l5blog/phpunit.xml

PHP Fatal error:  Call to a member function make() on a non-object in /Users/lee/.composer/vendor/illuminate/support/Illuminate/Support/helpers.php on line 33

Fatal error: Call to a member function make() on a non-object in /Users/lee/.composer/vendor/illuminate/support/Illuminate/Support/helpers.php on line 33

Anyone know what's wrong & how I can fix?

bobbybouwmann's avatar

@lstables we need to see code from to test to help you ;) Why don't you create a new thread so we can help you out. Then we can keep this thread for the conversation about the new package from Jeffrey :D

vincej's avatar

I've always wanted to get into testing but to be honest, the set up and learning curve seems so laborious that I have never found the energy. Instead as an independent teamless provider still working to make the cross over from CodeIgniter to Laravel, I have always relied upon thorough user scenario testing - which is essentially testing the crap out of the product, under different prescribed what if scenarios.

So, far it has worked very well. My CI apps run fast as lighting and have no known bugs.

Still - I want to up my skills and join the Laravel World want to do things "properly" - So, if Jeff's tool takes the grunt out of it, then all the better!

kfirba's avatar

@JeffreyWay I think I'm a little bit confused. You are doing an integration test through the browser (or at-least mimic a request)? isn't it tightly coupling your tests to the browser while you may want to test a repository that you may not only use in your browser but maybe through the command line as-well? I believe I'm missing something here :/ Can you tell me what is it please?

JeffreyWay's avatar

@kfirba - No, we're not tightly coupling anything here. If you want to test a repository, then test a repository. That has nothing to do with how we test some kind of functionality in our app.

kfirba's avatar

@JeffreyWay Isn't it safe to say that our repositories tests are referred as "integration tests"? In the code that you showed it seems like you are visiting URLs. Maybe my misunderstanding is because I'm not entirely sure what you mean when you say integration tests. How do you see integration tests? what exactly are they?

JeffreyWay's avatar

@kfirba - An integration test is nothing more than when we combine multiple parts of our system and test them.

So you could write an integration test for a repository that throws a couple test rows in a table, performs the query, and then verifies the results. Or you could write a test that verifies that your sign up process works correctly.

Some might call the examples from my first comment functional tests. That's fine. But functional tests are a type of integration test.

Either way, no, we're not coupling anything to anything.

dertechniker's avatar

Sadly, i never tested anything before. I really want to, but then i ask myself: why should i do all that work? I first even have to LEARN how to make tests and this is eve more work.

kfirba's avatar

@JeffreyWay I see, thanks.

Won't it be better if I test my sign up functionality with some tool like behat? I will then be able to test it against a domain layer and a UI layer.

Your syntax is very much like Mink's syntax. What are the differences? If I had to guess, I would say that Mink needs Selenium/Goutte etc and the code you presented here needs absolutely nothing? I guess your code is calling the call() method which triggers a route call without a browser

davorminchorov's avatar

@dertechniker Testing has its own pros and cons and here are a few of them:

Pros

  • Easier way to find bugs
  • You test and build the app in the same time
  • You test and find bugs faster
  • You are sure that your app is working as expected
  • You will know if something broke during your last refactor / addition.

Cons

  • Takes time to write tests
  • Takes time to learn how to write tests

Read a few blog posts on testing in general and you'll understand more why testing is important.

I didn't know anything about testing before I joined Laracasts. Now I feel like I gotta test everything in detail in order to make sure everything works as expected!

Oh, by the way, this PHPUnit package looks awesome! :)

Next

Please or to participate in this conversation.