I previously talked about organising your test suites and one of the great benefits you get from doing so is that you are then able to run your tests in many different ways and configurations, so that the right tests get run at the right time.

Running specific tests and test classes

As I am writing code, I'm usually practicing TDD and writing my tests before writing and refactoring code. This usually means I have a test class open and at least the corresponding code class open in splits on the screen. I move back and forth between the splits, writing test code, production code and refactoring. If I were to run the whole test suite every time I've finished writing something, it would make the feedback loop too slow for me on even a medium sized project. As I write a test, if the whole set of tests in the class run very quickly, I might run them all by asking PHPUnit to run that test file, allowing me to quickly check the correctness of the test I'm working on, that it's failing and that the production code I write then makes it pass.

phpunit tests/integration/App/Controller/AccountControllerTest.php

However, usually I prefer to run just that single test that I am working on right now. PHPUnit has a filter switch, which makes this possible, though it can be a little fiddly.

phpunit --filter test_it_should_deny_unauthenticated_requests tests/integration/App/Controller/AccountControllerTest.php

I'll then run the full test class after I've finished refactoring, ensuring that I haven't affected any related code.

Vim Bindings

In order to facilitate this, I use a set of vim key bindings, mostly inspired by watching Gary Bernhardt's Destroy all Software.

<leader>t If I am in a PHPUnit test file, save and run the file. If I am not in a test file, save the file I am in and run the last test file I ran.

<leader>s If I am in a PHPUnit test file, save the file and run the test case the cursor is in. If I'm not in a test file, save the current file and run the last test case I ran.

vim bindings

I love how quick and easy this makes running the tests and because I use terminal vim, I run them right there using bang(!) and my attention doesn't leave the current window. Hitting enter dismisses the results.

I also have a few other key bindings set up, though I don't use them all that often.

<leader>Tc Run PHPUnit with code coverage on the current test file, or the last test file if looking at production code.

<leader>Td Run PHPUnit with TestDox output on the current file or the last run test file if looking at production code.

<leader>T Run PHPUnit without any arguments, so the default test suite as per the phpunit.xml configuration.

There are a whole host of ways to set this kind of thing up with Vim. Some people like to have Vim send commands to a tmux pane and have the results show there.

Whatever your favourite editor is, it might be worth seeing what sort of support they have for running tests.

Running with filesystem watchers

It's always my preference to run the tests whenever I see fit, but if your editor doesn't make it easy, or if it doesn't suit your workflow, perhaps some of the file watcher setups could be right for you.

These tools watch the filesystem and run PHPUnit for you whenever a file is updated. I think most people have them running in a window on screen, but I know some of them show you pass/fail notifications via growl and such.

I think one of the most well known tools is Ruby's combination of guard and rspec, but Eric Hogue has a post on how he uses guard with his PHPUnit tests. There are loads of other tools, a quick search shows there are a bunch of packages available for grunt and gulp, I'm sure one of them works. If you use one and really like it, comment below or tweet at me and I'll update this post with details.

Groups/Suites

Moving on from the inner TDD loop, having your test suite organised into directories, suites or groups can be really beneficial for running on workstations. Sometimes we have tests that are slow to run or simply can't be run due to hardware, operating system, licencing or networking, so making sure developers can run a reasonable set of tests before commiting or merging code is essential. Giving the developers a choice of different runs can make the feedback loop more pleasant, meaning the tests get run more often, but not so often that you're wasting developer time and CPU cycles.

Continuous Integration

Here is the place to make sure all of the tests get run at some point. My preference would be for all tests to run before code is released. However, if you have some tests that are too hard or to slow to run before every release (assuming you've done everything you can to fix those tests), and the risk is acceptable, having those tests run in a different CI task is a good idea, allowing your release cycle to move quickly.

As mentioned in the organising your test suite post, being able to run your fastest tests first can help the test runs fail fast, meaning you get to work fixing the code faster.

Another quick tip, unrelated to testing itself, if you run any code coverage or static analysis on the code purely for metrics, have that run separately from the main release build, either automatically or on demand. These things take time and if a drop in code coverage or an increase in cyclomatic complexity wouldn't stop you from releasing code, make it part of a separate build/task.

Faster tests in PHP

This is the third in a series about keeping your test runs fast, check back for more or leave your email address below to get notified when a new post goes up.

  1. Avoiding latency with Fakes
  2. Organising Test Suites
  3. Selectively Running Tests