Laravel 5.1 Beauty - Testing

Starting the l5beauty project and doing just a bit of testing

In this chapter we’ll create a project to use throughout the rest of the book and explore various options for testing. Along the way a service class to convert Markdown formatted text files to HTML will be developed.

Running PHPUnit

Did you get an error?

If you receive a command not found or a permissions denied
error when attempting to run the
phpunit command it could be because of an installation bug. The phpunit
command should be found in the vendor/bin directory—and this directory
was added to the path in your Host OS back in Chapter 3 or 4. The problem
is that the Laravel command has a bug that doesn’t necessarily set the
permissions correctly on phpunit and several other utilities.

To fix this bug, follow the two steps below.

Step 1 - Delete the vendor directory. Just wipe it out using whatever
command is appropriate for your Host OS.

Laravel 5.1 Crawler Methods and Properties

The Crawler tests allow you to test pages in your web application. The nice thing is that many of these tests are fluent and return $this, allowing you to build the ->visit()->see() type test in the above example.

Here are some of the available properties and methods.

$this->response

The last response returned by the web application.

$this->currentUri

The current URL being viewed.

visit($uri)

(Fluent) Visit the given URI with a GET request.

get($uri, array $headers = [])

(Fluent) Fetch the given URI with a GET request, optionally passing headers.

post($uri, array $data = [], array $headers = [])

(Fluent) Make a POST request to the specified URI.

put($uri, array $data = [], array $headers = [])

(Fluent) Make a PUT request to the specified URI.

patch($uri, array $data = [], array $headers = [])

(Fluent) Make a PATCH request to the specified URI.

delete($uri, array $data = [], array $headers = [])

(Fluent) Make a DELETE request to the specified URI.

followRedirects()

(Fluent) Follow any redirects from latest response.

see($text, $negate = false)

(Fluent) Assert the given text appears (or doesn’t appear) on the page.

Specify a list of events that should be fired for the given operation.

withoutEvents()

Mock the event dispatcher so all events are silenced.

expectsJobs($jobs)

Specify a list of jobs that should be dispatched for the given operation.

withSession(array $data)

Set the session to the given array.

session(array $data)

Starts session and sets the session values from the array.

flushSession()

Flushes the contents of the current session.

startSession()

Starts the application’s session.

actingAs($user)

(Fluent) Sets the currently logged in user for the application.

be($user)

Sets the currently logged in user for the application.

seeInDatabase($table, array $data, $connection = null)

(Fluent) Asserts a given where condition exists in the database.

notSeeInDatabase($table, $array $data, $connection = null)

(Fluent) Asserts a given where condition does not exist in the database.

missingFromDatabase($table, array $data, $connection = null)

(Fluent) Alias to notSeeInDatabase().

seed()

Seeds the database.

artisan($command, $parameters = [])

Executes the artisan command and returns the code.

Any of these methods or properties can be accessed within your test classes. The provided ExampleTest.php file contains a line using $this->call(...) inside the testBasicExample() method.

Laravel 5.1 PHPUnit Assertions

In addition to the standard PHPUnit assertions (such as assertEquals(), assertContains(), assertInstanceOf(), …), Laravel 5.1 provides many additional assertions to help write tests dealing with the web application.

Using Gulp for TDD

Gulp is a build and automation system written in Javascript. It allows common tasks such as minification of source files to be automated. Gulp can even watch your source code for changes and automatically run tasks when this occurs.

Laravel 5.1 includes Laravel Elixir which allows Gulp tasks to be built in easy ways. Elixir adds an elegant syntax to gulp. Think of it this way … what Laravel is to PHP, Elixir is to Gulp.

One of the most common uses of Gulp is to automate unit tests. We’ll follow the TDD (Test Driven Development) process here and let Gulp automatically run our tests.

Configuring Gulp to run PHPUnit Tests

Here we call the elixir() function, passing a function. The mix object this function will receive will be a stream on which multiple things can happen. You might want to build LESS files into CSS files here, then concatenate those CSS files together, and then provide versioning on the resulting concatenated files. All of those things can be specified by using a fluent interface on the mix object.

But for now, we’re only running PHPUnit tests.

Next, from the project root on your Host OS, run gulp to see what happens.

Running Gulp

The command will just hang there, watching for source file changes and running unit tests when needed.

To see how this works, let’s break the existing unit test.

Change the see() line in tests/ExampleTest.php to what’s below.

Breaking ExampleTest.php

->see('Laravel 5x');

When you save this file, gulp will notice and run PHPUnit again. The will fail and you will see a notice on your computer similar to the one below.

Figure 6.3 - Gulp’s PHPUnit Failure on Mac

Change the line back to what it was before, save it, and again gulp will run PHPUnit. This time you should receive a notice indicating you are “back to green”.

To exit Gulp’s tdd mode

Simply press Ctrl+C

Creating a Markdown Service

The blogging application we’ll be building will allow editing posts in Markdown format. If you aren’t familiar with Markdown, check out the link. It’s an easy-to-read and easy-to-write format that transforms easily to HTML.

To illustrate testing, we’ll build a service to convert markdown text to HTML text using TDD.

Pulling in Markdown Packages

There are many PHP packages out there for converting Markdown to HTML. If you go to http://packagist.org and search for markdown there are twenty pages of packages.

We’ll use the package created by Michel Fortin because there’s another package called SmartyPants by the same author that converts quotation marks to the nice looking curly quotes.

Did you notice that the specific version of the package was specified when requiring SmartyPants? This is because at the time of this writing there isn’t a stable package that can be pulled in automatically.

Creating the Markdown Test Class

The first thing to do when starting a TDD session is to fire up Gulp in TDD mode.

Have the setup() method create a new instance of the Markdowner class. (Yes, this doesn’t exist yet.)

Line 13

A simple test we know should work.

You should have received a failure notice. (If you didn’t Ctrl+C out of Gulp and restart it.)

Even though a notice appeared saying the test failed, sometimes it’s useful to look at the console to determine what the failure was. In this case, it’s pretty obvious. The App\Services\Markdowner class doesn’t exist.

Creating the Markdowner Service

What we’ll do here is create a simple service that wraps the php-markdown and php-smartypants packages we imported earlier.

In the app\Services directory create a Markdowner.php file with the following contents.

In case we want to later do our own transformations before anything else.

Line 25

Like preTransformText(), but this time if we later want to add our own final transformations.

When you save this file, Gulp should notice and you will receive a “GREEN” alert telling you everything worked as expected.

If you don’t receive the green alert, go back and check for typos in both the App\Services\Markdowner and MarkdownerTest classes.

A Few More Tests

Admittedly, this isn’t a great example of TDD because it’s simple a test and a complete class created to fix the test. In actual practice TDD would have many more iterations, resulting in a flow like the one below:

Create MarkdownerTest w/ testSimpleParagraph()

Tests Fail

Create Markdowner class, hardcoding toHTML() to pass the test

Tests Succeed

Update Markdowner class to use MarkdownExtra

Tests Succeed

Add a testQuotes() to MarkdownerTest class

Tests Fail

Update Markdowner class to use SmartyPants

Tests Succeed

And so forth. Even the structure of our Markdowner class is flawed when it comes to testing. To do pure unit testing on this class it should be structured such that instances of both the MarkdownExtra and SmartyPants classes are injected into the constructor. This way our unit test could inject mock objects and only verify the behavior of MarkdownExtra and not the classes it calls.

But this isn’t a book on testing. In fact, this is the only chapter where testing is discussed. We’ll leave the structure as is but add just a couple more tests.

Here we changed the test class to test multiple conversions at once and added three tests in conversionsProvider(). Your tests should be green before moving forward.

Once the tests are green hit Ctrl+C in your Host OS console to stop Gulp.

Other Ways to Test

It’s not the intent here to provide a definitive list of all the ways to test with Laravel 5.1 because there’s really no single way to do testing in PHP. Therefore, there’s no single way to test in Laravel 5.

But, we’ll explore some alternatives.

phpspec

Besides PHPUnit, Laravel 5.1 also provides phpspec out of the box. This is another popular PHP test suit with more of a focus on Behavior Driven Development.

Here’s a few notes on phpspec.

The binary is in vendor/bin, thus you can call phpspec from your project’s root directory.

The configuration file is in the project root. It’s named phpspec.yml.

To run phpspec from Gulp, Elixir provides the phpSpec() function you can call on the mix object.

If you change your application’s namespace from App to something else, be sure to update phpspec.yml accordingly.

Unit Testing

Although PHPUnit is the standard when it comes to PHP unit testing, there are other packages you can use.

Enhance PHP - A unit testing framework with support for mocks and stubs.

Functional / Acceptance Testing

These tests actually use your application instead of just verifying that units of code within your application work. When using the fluent test methods Laravel 5.1 provides you can actually do some functional tests using PHPUnit. ExampleTest.php shows a simple example. But there are other testing frameworks that focus on functional / acceptance testing.

Codeception - Problem the most popular framework for acceptance testing.

Behavior Driven Development

SpecDD focuses on the technical aspects of your code. Laravel 5.1 includes phpspec which is the standard for SpecDD.

StoryBDD emphasizes business or feature testing. Behat is the most popular StoryBDD framework. Although, Codeception can also be used for StoryBDD.

Recap

The first thing we did in this chapter was creating a project named l5beauty. Then we explored unit testing using PHPUnit within this project. Finally, we created a Markdowner service class for the dual purposes of having something to test and to use later to convert markdown text to HTML.

This was a pretty long chapter because testing is a large topic and a single chapter cannot give it justice. But, as I’ve mentioned, testing is not the focus of this book. There will be no more testing in subsequent chapters.