SnapShooter Backups Server, Database, Application and Laravel Backups - Get fully protected with SnapShooter

PHPUnit tips

In this tutorial, we will go though some tips we gathered over the years of using PHPUnit. It is not an introduction to PHPUnit, you should already be familiar with PHPUnit before you continue reading this tutorial. For those who need an introduction to PHPUnit, please go through tutorials at PHPUnit Beginner.

Clear naming of test methods

A clear name of a test method goes a long way. It helps us understand the test cases easily, instead of digging into its method implementation detail. It also helps others get a quick idea of what our public APIs are capable of.

It is very important to name our test methods with clear intend. So we shall not be afraid of long method names.

An example from one of our projects:

public function testRegister_shoud_throw_exception_when_verification_code_is_invalid
{
 
}

Class::class constant for referencing full-qualified class name

Namespace feature in PHP has helped us solve the class name conflict issues very well. However Typing a long full-qualified class name in our PHPUnit classes is tedious job.

PHP's class constant helps us avoid to type long and unreadable full-qualified class names in our PHPUnit classes. The class constant is introduced in PHP 5.5.

Whenever we need to provide a full-qualified class name, we can make use of the class constant.

For example, to mock a QueueManager object defined in a namespace, we can do:

$queueManger = $this->getMock(QueueManager::class);

Note in the code above, we didn‘t have to specify the full-quality class name thanks to the class constant.

Exception without annotations

Prior to PHPUnit 5.2, to test whether an exception is thrown, we would normally use annotation. For example, the test case below tests whether an RuntimeException exception is thrown during its execution.

?

/**
 * @expectedException \RuntimeException
 */
public function testDivide_runtime_exception_must_throw()
{
    $this->math->divide(1,0);
}

There are a few issues with annotation approach.

First we can’t use the class constant in annotation comment. For example, if we expect the method to throw an exception that is in a particular namespace. We have to supply a full-qualified name of the exception class. The code as shown below demonstrates the point:

/**
 * @expectedException App\Model\Core\CoreException
 */
public function public function testDivide_runtime_exception_must_throw()()
{
    $this->math->divide(1,0);
}

As we can see, it is hard to read and maintain if we have to type a full-qualified class name in the annotation comment.

Second issue with the annotation approach is that it is unable to specify which method is expected to raise an exception exactly. As long as a matching exception is raised in the test method, PHPUnit will treat it as a successful test.

For example, in the code below, we expect an RuntimeException is raised in method divide(). But if RuntimeException is raised from the constructor (new Math()), PHPUnit will still consider it as a passing test.

/**
 * @expectedException \RuntimeException
 */
public function testDivide_runtime_exception_must_throw()
{
    $this->math = new Math();
    $this->math->divide(1,0);
}

The solution to the issues above will be a new method introduced in PHPUnit 5.2. It's expectException(). Just like using regular assert(), expectException() method expects the code below it to throw a specified exception. Since it is a class method, we can use the class constant when passing the expected exception class.

To solve the two issues mentioned earlier with expectException(), we do something similar to the code as shown below:

public function testDivide_runtime_exception_must_throw()
{
    $this->math = new Math();
 
    $this->expectException(CoreException::class);
 
    $this->math->divide(1,0);
}

The End

Hopefully this simple tutorial helped you with your development . If you like our post, please follow us on Twitter and help spread the word . We need your support to continue. If you have questions or find our mistakes in above tutorial, do leave a comment below to let us know .