Unit testing part 2: Writing and running tests

June 10, 2009 – 1:44 pm Tags: ,

Continuing from the unit test introduction, we will now continue and take a look at how to write tests and ways to run the tests.

Setting up PHPUnit

Before we can write tests, we need a testing tool. We are going to use PHPUnit for our examples, so you will need to install it.

The easiest way to install it is through PEAR. Read the PHPUnit installation guide for information on how to do that.

You will also need to be able to run PHP on the command line, including the phpunit command-line script. If you’re on Linux, chances are you already have PHP available on the command line – if not, the package for installing command-line PHP is usually something like php5-cli or such.

I have previously written a post on setting up command-line PHP on windows, which you can read to make it work on Windows.

To confirm everything works as expected, run a shell or command prompt and type in:

phpunit --version

which should output something like this:

PHPUnit 3.3.17 by Sebastian Bergmann.

Using PHPUnit

Next, let’s take a look at how to use PHPUnit so that we know how to use it when we actually start writing some real tests.

Writing a testcase

PHPUnit tests are written as testcase classes, which extend PHPUnit_Framework_TestCase. Let’s take a simple example to show you how they work.
For this example, we will just write a quick test for PHP’s array and count function.

class ArrayTest extends PHPUnit_Framework_TestCase {
  public function testAddingItemsIncreasesLength() {
    $array = array();
    $expectedLength = count($array) + 1;
 
    $array[] = 'foo';
    $this->assertEquals($expectedLength, count($array), 'Length was not correct');
  }  
}

As you can see from the code here, our test class is called ArrayTest and it extends from the PHPUnit testcase class. The naming convention for classes such as this is usually ClassNameTest – for example, a testcase for Zend_Controller_Action would be called Zend_Controller_ActionTest.

The ArrayTest class contains one method: testAddingItemsIncreasesLength. This is a test method. The convention for PHPUnit is that test methods are named testDescriptionOfWhatIsTested, so since our test checks that when we add an item into the array, the count is increased by one, our test is called testAddingItemsIncreasesLength. You can write as many test methods in a testcase as you think is necessary.

The code in the test method should be quite easy to understand – we create an array, calculate what the expected length of the array should be, push an item into the array and finally we have an assertion that confirms the result is as we expected. You can find a list of assertions you can do in the PHPUnit manual.

Running tests

Now that we have a test, how do we run it? These are the usual ways to do it:

  1. The most straightforward way is to run a single testcase with phpunit, like this: phpunit NameOfTest, so to run our ArrayTest, we can do phpunit ArrayTest. Note that this assumes you are in the directory where the test is saved, and that the filename is ArrayTest.php.
  2. Writing a test suite. This is complex and annoying to maintain, so I won’t go into it any more. If you really want to know, there’s a chapter on it in the PHPUnit manual.
  3. Using an XML configuration file. This is the easiest way to run multiple tests, so we’ll take a look at writing this next.

Since most of the time you’ll want to run all of your tests, or you have more than one test that you want to run, doing it manually with phpunit SomeTest isn’t very feasible. Option #2 can be used to run multiple tests in one go, but as said, it’s not exactly a very good method.

So to run multiple tests, we’ll use method #3 – an XML configuration file. This file can be named whatever you want, but it’s probably a good idea to call it phpunit.xml because that means phpunit will detect it automatically.

Here’s an example phpunit.xml configuration file:

<phpunit>
	<testsuite name="Test suite name">
		<directory>path/to/tests</directory>
	</testsuite>
</phpunit>

This is the simplest possible xml configuration. All we define is a testsuite element with a name attribute, and a path to the tests.

The typical directory layout for tests is like this:

project/tests
project/tests/phpunit.xml
project/tests/App/SomeClassTest.php (this is a test for class App_SomeClass)

In this case, you would set the directory in the phpunit.xml file to . to tell it the tests are in the current dir, like this:

<phpunit>
	<testsuite name="My tests">
		<directory>.</directory>
	</testsuite>
</phpunit>

Using this kind of a configuration file, we can now easily run all our tests by just typing phpunit on the command-line, and phpunit will then read the config and execute all tests, providing us with feedback about the process.

The configuration file has other options you can add to it too. We won’t look at other properties in this post, but you can find a list of configuration options from the PHPUnit manual.

Next week’s post

Next week we will finally get to actually writing some tests for some example methods. We’ll take a look at a class or two, and look at how to write good tests for it: Unit testing 3: writing tests for existing code

I’d like to apologize to those of you who were waiting for that to show up in this week’s post – I kind of forgot that explaining how to run tests and all that would need it’s own post, and posting that before going any further made more sense.

Share this:
  1. 14 Responses to “Unit testing part 2: Writing and running tests”

  2. All right. I will look for the next post in this series.

    By Sudheer on Jun 10, 2009

  3. Interesting post.

    I personally think that the future is all about unit testing

    By Ian Hickman on Jun 10, 2009

  4. Hi there,

    I wrote a lot of code in my company. And week by week our users find some minor bugs. Thats annoying and I have less time to code new things. So I´d like to work with unit tests, but how can I write these test for a application that has hundertthousend lines of code?
    But the most considerable thing is: How can I test database interactions without deleting, inserting and editing tables?

    By MaikL on Jun 11, 2009

  5. The amount of code doesn’t really matter as long as the code is divided into some reasonable chunks of classes and methods (or even functions, but they’re often more tricky to test)

    You simply take one class at a time and write tests that check that it behaves as expected in different cases. I’ll talk more about doing that in next week’s post.

    Database interactions can often be tested by mocking the DB object’s if your system separates all DB interactions into specific classes – basically it means you create “fake” DB objects, and your code in tests calls those.

    An alternative is to create a new database just for testing code, which is only used for that purprose and so it won’t matter if the tests screw with the data. Sometime in the future I’ll probably write a post about testing database interactions as well.

    By Jani Hartikainen on Jun 11, 2009

  6. Hi Jani,

    one could argue that your example is not that good or incomplete.
    Using the same function (count() in your example) to define the expected and test for the actual value doesn’t feel right.
    Personally, i would either write a small test for count() above or below your example test, or swap out $expectedLength = count($array) + 1; for $expectedLength = 1;.

    Also, I personally prefer the Testsuites Stuff. As this usually comes with a tree structure, i can very easily run only parts of the tree ;)
    This is extremely useful if the full suite runs some minutes, but the test(s) you are working just need some seconds.

    By Karsten Deubert on Jun 12, 2009

  7. Yeah the example here is probably a bit simple, which is the purprose too, but thanks for the feedback.

    You can actually use the –filter command line parameter with the configuration file approach to just run the tests you want, though it probably won’t be simple to run trees. Personally I find the maintenance of a testsuite class too tedious – if it was generated automatically, then it might be a different matter.

    By Jani Hartikainen on Jun 12, 2009

  8. My precious Zend Studio has phpunit testsuite codegeneration :)

    By Karsten Deubert on Jun 12, 2009

  1. 7 Trackback(s)

  2. Jun 10, 2009: Jani Hartikainen’s Blog: Unit testing part 2: Writing and running tests | Webs Developer
  3. Jun 11, 2009: Jani Hartikainen’s Blog: Unit testing part 2: Writing and running tests
  4. Jun 11, 2009: Jani Hartikainen’s Blog: Unit testing part 2: Writing and running tests
  5. Jun 17, 2009: Unit testing part 2: Writing and running tests | Dailytuts.net
  6. Jul 4, 2009: Unit testing: Introduction | CodeUtopia
  7. Jul 4, 2009: Unit testing 3: Writing tests for existing code | CodeUtopia
  8. Nov 26, 2009: Unit testing in PHP | Behind The View

Post a Comment

You can use some HTML (a, em, strong, etc.). If you want to post code, use <pre lang="PHP">code here</pre> (you can replace PHP with the language you are posting)