PHPUnit: Basics of Unit Testing

What is Unit Testing ?

Unit Testing is a software testing method by which individual units of code are tested to determine if they are fit to use.

Benefits of Unit Testing

- find problems early
- facilitates changes
- simplifies integration
- documentation
- design interface

What is PHPUnit?

- xUnit-style library by Sebastian Bergmann
- Installable via Composer, PEAR and Phar
- well integrated and well documented
reference: http://phpunit.de/manual/current/en/index.html

Installation (globally via Phar)
wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/bin/phpunit
source: http://phpunit.de/manual/current/en/installation.html

Installation (as vendor via Composer)
Create a composer.json file in the root directory then add the ff.:
{
    "require-dev" : {
        "phpunit/phpunit" : "4.8.0"
    },
    "autoload" : {
        "psr-4" : {
            "Project\\" : "app/"
        }
    }
}

The require-dev will simply install the development version of phpunit/phpunit package along with its dependencies.

The autoload maps the app/ directory to CodeProject namespace which we can then call in our unit tests. The ideal project directory structure is as follows:
| - app
| - tests
| - vendor
composer.json
But don't create the vendor directory yet. Composer will do it upon installation.
Next, run the ff. command to install PHPUnit.
composer install
If you have done changes to composer.json, then make sure to run composer update

Create the PHPUnit Configuration file
Set up the PHPUnit config file phpunit.xml in the same directory as composer.json. Here's a basic test suite.
<?xml version="1.0" encoding="utf-8" ?>
<phpunit colors="true" verbose="true" bootstrap="./vendor/autoload.php">
    <testsuites>
        <testsuite name="The project's test suite">
            <directory>./tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

What it does basically is that it tells PHPUnit that our test cases are in the ./tests directory and that it must load ./vendor/autoload.php first before running the test so we do not have to specify them whenever we execute phpunit in the console.

Writing Tests

1. The tests for a class Product go into a class ProductTest
2. ProductTest inherits (most of the time) from PHPUnit_Framework_TestCase
3. The tests are public methods that are named test*
// ex. getPrice() → testGetPrice()
4. Inside the test methods, assertion methods are used to assert that an actual value matches an expected value

Assertions

- assertEmpty( $actual )
- assertEquals( $expected, $actual )
- assertTrue( $condition )
- assertFalse( $condition )
- assertCount( $expected_count, $haystack )
more: http://phpunit.de/manual/current/en/appendixes.assertions.html

Example

app/product.php
namespace Project;

class Product
{
 public function isAvailable() {
  return true;
 }
}

tests/ProductTest.php
class ProductTest extends PHPUnit_Framework_TestCase
{
        protected function setUp() {
            $this->product = new Project\Product;
        }

 public function testIsAvailableIsTrue() {
  $this->assertTrue($this->product->isAvailable());
 }

        public function testIsAvailableIsFalse() {
  $this->assertFalse($this->product->isAvailable());
 }
}

In the setUp() method, we assign a new instance of the Product class in the $this->product variable. The setUp() method will always be invoked before the first tests, which in this case is testIsAvailableIsTrue()

Running the Test
./vendor/bin/phpunit

If you have not created the phpunit.xml configuration file, then you may run the test manually as follows:

./vendor/bin/phpunit tests --bootstrap ./vendor/autoload.php

To test a specific class, you must specify it also:

./vendor/bin/phpunit tests/ProductTest --bootstrap ./vendor/autoload.php

To see this in action, clone this repository https://github.com/hanapiers/phpunit-basic-setup

The result should display something like:
FAILURES!
Tests: 4, Assertions: 4, Failures: 2.

Comments