Introduction

PHPUnit is one of the oldest and most well known unit testing packages for PHP. It is primarily designed for unit testing, which means testing your code in the smallest components possible, but it is also incredibly flexible and can be used for a lot more than just unit testing.

PHPUnit includes a lot of simple and flexible assertions that allow you to easily test your code, which works really well when you are testing specific components. It does mean, however, that testing more advanced code such as controllers and form submission validation can be a lot more complicated.

The purpose of this tutorial is to introduce you to the basics of PHPUnit testing, using both the default PHPUnit assertions, and the Laravel test helpers. The aim is for you to be confident writing basic tests for your applications by the end of the tutorial.

Prerequisites

This tutorial assumes that you are already familiar with Laravel and know how to run commands within the application directory (such as php artisan commands). We will be creating a couple of basic example classes to learn how the different testing tools work, and as such it is recommended that you create a fresh application for this tutorial.

If you have the Laravel installer set up, you can create a new test application by running:

laravel new phpunit-tests

Alternatively, you can create a new application by using Composer directly:

Creating a New Test

The first step when using PHPUnit is to create a new test class. The convention for test classes is that they are stored within ./tests/ in your application directory. Inside this folder, each test class is named as <name>Test.php. This format allows PHPUnit to find each test class — it will ignore anything that does not end in Test.php.

In a new Laravel application, you will notice two files in the ./tests/ directory: ExampleTest.php and TestCase.php. The TestCase.php file is a bootstrap file for setting up the Laravel environment within our tests. This allows us to use Laravel facades in tests, and provides the framework for the testing helpers, which we will look at shortly. The ExampleTest.php is an example test class that includes a basic test case using the application testing helpers – ignore it for now.

To create a new test class, we can either create a new file manually – or run the helpful Artisan make:test command provided by Laravel.

In order to create a test class called BasicTest, we just need to run this artisan command:

The most important thing to notice here is the test prefix on the method name. Like the Test suffix for class names, this test prefix tells PHPUnit what methods to run when testing. If you forget the test prefix, then PHPUnit will ignore the method.

Before we run our test suite for the first time, it is worth pointing out the default phpunit.xml file that Laravel provides. PHPUnit will automatically look for a file named phpunit.xml or phpunit.xml.dist in the current directory when it is run. This is where you configure the specific options for your tests.

There is a lot of information within this file, however the most important section for now is the testsuite directory definition:

Next, open your ./tests/BasicTest.php class (that we created earlier), and remove the testExample method that was created by default. You should be left with an empty class.

We will now use seven of the basic PHPUnit assertions to write tests for our Box class. These assertions are:

assertTrue()

assertFalse()

assertEquals()

assertNull()

assertContains()

assertCount()

assertEmpty()

assertTrue() and assertFalse()

assertTrue() and assertFalse() allow you to assert that a value is equates to either true or false. This means they are perfect for testing methods that return boolean values. In our Box class, we have a method called has($item), which returns true or false when the specified item is in the box or not.

This tells us that the assertion on line 12 failed to assert that a false value was true – as we switched the assertFalse() for assertTrue().

Swap it back, and re-run PHPUnit. The tests should again pass, as we have fixed the broken test.

assertEquals() and assertNull()

Next, we will look at assertEquals(), and assertNull().

assertEquals() is used to compare the actual value of the variable to the expected value. We want to use it to check if the value of the takeOne() function is an item that is current in the box. As the takeOne() method returns a null value when the box is empty, we can use assertNull() to check for that too.

Unlike assertTrue(), assertFalse(), and assertNull(), assertEquals() takes two parameters. The first being the expected value, and the second being the actual value.

assertContains(), assertCount(), and assertEmpty()

Finally, we have three assertions that work with arrays, which we can use to check the startsWith($item) method in our Box class. assertContains() asserts that an expected value exists within the provided array, assertCount() asserts the number of items in the array matches the specified amount, and assertEmpty() asserts that the provided array is empty.

Congratulations, you have just fully tested the Box class using seven of the basic PHPUnit assertions. You can do a lot with these simple assertions, and most of the other, more complex, assertions that are available still follow the same usage pattern.

Testing Your Application

Unit testing each component in your application works in a lot of situations and should definitely be part of your development process, however it isn’t all the testing you need to do. When you are building an application that includes complex views, navigation and forms, you will want to test these components too. This is where Laravel’s test helpers make things just as easy as unit testing simple components.

We previously looked at the default files within the ./tests/ directory, and we skipped the ./tests/ExampleTest.php file. Open it now, and it should look something like this:

We can see the test in this case is very simple. Without any prior knowledge of how the test helpers work, we can assume it means something like this:

when I visit / (webroot)

I should see ‘Laravel 5’

If you open your web browser to our application (you can run php artisan serve if you don’t have a web server set up), you should see a splash screen with “Laravel 5” on the web root. Given that this test has been passing PHPUnit, it is safe to say that our translation of this example test is correct.

This test is ensuring that the web page rendered at the / path returns the text ‘Laravel 5’. A simple check like this may not seem like much, but if there is critical information your website needs to display, a simple test like this may prevent you from deploying a broken application if a change somewhere else causes the page to no longer display the right information.

visit(), see(), and dontSee()

Let’s write our own test now, and take it one step further.

First, edit the ./app/Http/routes.php file, to add in a new route. For the sake of this tutorial, we will go for a Greek alphabet themed route:

Now open it in your browser to ensure it is working as expected: http://localhost:8000/beta, and it should display a friendly “This is the Alpha page.” message.

Now that we have the template, we will create a new test. Run the make:test command:

php artisan make:test AlphaTest

Then edit the test, using the example test as a guide, but we also want to ensure that our “alpha” page does not mention “beta”. To do this, we can use the dontSee() assertion, which does the opposite of see().

Save it and run PHPUnit (./vendor/bin/phpunit), and it should all pass, with the status line looking something like this:

OK (5 tests, 12 assertions)

Writing Tests First

A great thing about tests is that you can use the Test Driven Development (TDD) approach, and write your tests first. After writing your tests, you run them and see that they fail, then you write the code that satisfies the tests to make everything pass again. So, let’s do that for the next page.

First, make a BetaTest class using the make:test artisan command:

php artisan make:test BetaTest

Next, update the test case so it is checking the /beta route for “Beta”:

Notice that we aren’t checking the content of either page in our new testClickNextForBeta() test method. Other tests are successfully checking the content of both pages, so all we care about is that clicking the “Next” link will send us to /beta.

You can run the test suite now, but as expected it will fail as we haven’t updated our HTML yet.

We have broken our tests somehow. If you look at our new HTML carefully, you will notice we now have the terms beta and alpha on the /alpha and /beta pages, respectively. This means we need to slightly change our tests so they don’t match false positives.

Within each of the AlphaTest and BetaTest classes, update the testDisplays* methods to use dontSee('<page> page'). This way, it will only match the string, not the term.

Run your tests again, and everything should pass again. We have now tested our new pages, including the Next/Previous links between them.

Conclusion

You should notice a common theme across all of the tests that we have written in this tutorial: they are all incredibly simple. This is one of the benefits of learning how to use the basic test assertions and helpers, and trying to use them as much as possible. The simpler you can write your tests, the easier your tests will be to understand and maintain.

Once you have mastered the PHPUnit assertions we have covered in this tutorial, you can find a lot more in the PHPUnit documentation. They all follow the same basic pattern, but you will find that you keep coming back to the basic assertions for most of your tests.

Laravel’s test helpers are a fantastic compliment to the PHPUnit assertions, and make testing your application templates easy. That said, it is important to recognize that, as part of our tests, we only checked the critical information – not the entire page. This keeps the tests simple, and allows the page content to change as the application changes. If the critical content still exists, the test still passes, and everyone is happy.

Post navigation

Your email address will not be published. Required fields are marked *

Save my name, email, and website in this browser for the next time I comment.

About Stephen

Hi, I’m Stephen Rees-Carter, a senior developer, security analyst, and speaker from Brisbane, Australia. I spend most of my time working at Defiant (we make Wordfence), and the rest of it either on WithExtraVeg with my wife Gen, or some other small projects.