Be More Asssertive: Getting to Know PHPUnit’s Assertions+

Share this article

In my previous article
, I took you through some of the basics of unit testing with PHPUnit. I introduced you to what it means to test your code and the real benefits it can for you and your code. This time I want to dive in a little deeper and get to know PHPUnit in a bit more detail.

Key Takeaways

  • Utilize `markTestSkipped` and `markTestIncomplete` in PHPUnit to manage tests that cannot be executed or are unfinished, maintaining clarity in test outcomes.
  • Understand the importance of assertions in PHPUnit, such as `assertTrue` and `assertFalse`, which help verify conditions in your code with optional custom messages for clarity.
  • Explore mathematical assertions like `assertEquals`, `assertGreaterThan`, and `assertLessThanOrEqual` to validate numerical operations and relationships in your tests.
  • Employ string-specific assertions such as `assertStringEndsWith` and `assertStringMatchesFormat` to check the accuracy of string manipulations.
  • Leverage less common, yet useful assertions like `assertNull`, `assertSame`, `assertArrayHasKey`, and `assertInstanceOf` for more precise and varied test conditions.
  • Remember that good testing practices enhance code reliability and maintainability, allowing developers to modify code with confidence and reducing the risk of bugs.

Marking Tests Skipped or Incomplete

PHPUnit includes two methods that, if used correctly, can make your testing life a little simpler. The two methods, markTestSkipped and markTestIncomplete, allow your tests to have different results than just passing or failing. markTestSkipped gives you a bit of an “out” if a problem is encountered in the course of running your tests. Say you’re testing to see if a database record exists after the execution of a given method. In a perfect world, you’d always be able to connect to the database. What happens if you can’t, though? Well, your test would most certainly fail, since it couldn’t find the row. But that failing test might lead you to believe there was a problem with your code, even though there might not be. With the help of markTestSkipped, you can simply skip over that particular test in the current test run. Here’s an example:

<?php

public function testThisMightHaveADb()
{
  $myObject->createObject();

  try {
    $db = new Database();
    $this->assertTrue($db->rowExists());
  } catch (DatabseException $e) {
    $this->markTestSkipped('This test was skipped because there was a database problem');
  }
}
?>
There are three possible outcomes here. First, of course, if everything works as intended, the test will pass. It’s also possible that the assertTrue could fail, if the rowExists method returns false. But finally, and most interestingly, the database object could throw a DatabaseException type of exception. Our try/catch block will catch the exception, which indicates that the database is unavailable, and therefore that the whole point of the test is moot. Instead of failing, it just skips the test. The “skipped” result will still show up in all of your testing runs, so you’ll still be made aware that the issue will need to be resolved eventually. The markTestIncomplete method provides us with similar functionality, but with a different twist. It’s intended to give you a way to mark a test as, big surprise, incomplete. What this means is that if you begin writing a test, and intend to come back to it later to finish it, you can make it clear in the test results that it’s not a failure of the application code, but rather an incomplete test. You can even define a custom message so you’ll know why a test was skipped:
<?php

public function testAreNotEnoughHours()
{
  $this->markTestIncomplete("There aren't enough hours in the day to have my tests go green");
  $trueVariable = true;
  $this->assertTrue($trueVariable);
}
?>
It’s important to note that these two methods are a convenience only, and shouldn’t be an excuse for you to write sloppy tests. Your application is only as good as the tests that support it, so be sure to revisit any incomplete or skipped tests once you’re done working on the primary functionality you’re testing.

Assertions, Assertions, Assertions

In the last article, I reviewed a number of often-used assertions provided by PHPUnit. Now, we’ll review them and put them into practice in some sample code to show you how they’re used. Let’s start out with the sample class we’ll be testing:
<?php

class Testable
{
  public $trueProperty = true;
  public $resetMe = true;

  public $testArray = array(
    'first key' => 1,
    'second key' => 2
  );

  private $testString = "I do love me some strings";

  public function __construct()
  {
  }

  public function addValues($valueOne,$valueTwo) {
    return $valueOne+$valueTwo;
  }

  public function getTestString()
  {
    return $this->testString;
  }
}

?>
Let’s also set up our test class. This will be the container we drop the rest of the tests into so they can run against our Testable class:

<?php

class TestableTest extends PHPUnit_Framework_TestCase
{
  private $_testable = null;

  public function setUp()
  {
    $this->_testable = new Testable();
  }

  public function tearDown()
  {
    $this->_testable = null;
  }

  /** test methods will go here */
}

?>
We’re using the setUp and tearDown methods to prepare for our test run. I mentioned those methods briefly in the last article, but now it’s time to put them to use. The setUp method will be run before all of the tests in the test class, and tearDown will be run after all the test methods. In this case, we’re just creating a new instance of our Testable class and storing it so we can easily access it in each test method.

True or False

Now that we’ve got an instance of our class to test, let’s get into our assertions. PHPUnit makes it super simple to test your application one little bit at a time. Remember, the point of unit tests is to test “units” of code, not the whole flow of the application. If you’re tracing paths through your application, you’re probably doing it wrong. There are, of course, exceptions to the rule, but it’s a handy one to follow. Let’s get started with some of the simplest assertions—assertTrue and assertFalse.
<?php

public function testTruePropertyIsTrue()
{
  $this->assertTrue($this->_testable->trueProperty,"trueProperty isn't true");
}

public function testTruePropertyIsFalse()
{
  $this->assertFalse($this->_testable->trueProperty, "trueProperty isn't false");
}

?>
We looked at assertTrue and assertFalse in the last article, but we’ve added a twist here. See that handy message as the second parameter each assertion? This lets you define a custom message to be output if the test fails, rather than the default PHPUnit output, which can sometimes be a little cryptic. “Failed asserting that is false” won’t help you understand what’s wrong with your application code, but a message like “could not create user” is much more helpful!

Mathemagic

Next up we’ll look at some of the more mathematically oriented assertions. These let you evaluate the variables passed in to see how they relate. Let’s throw them all into one big test for the sake of illustration:
<?php

public function testValueEquals()
{
  $valueOne = 4;
  $valueTwo = 2;
  $this->assertEquals($this->_testable->addValues($valueOne,$valueTwo),6);
}
public function testValueGreaterThan()
{
  $valueOne = 4;
  $valueTwo = 2;
  $this->assertGreaterThan($valueTwo,$valueOne);
}
public function testLessThanOrEqual()
{
  $valueOne = 4;
  $valueTwo = 2;
  $this->assertLessThanOrEqual($valueTwo,$valueOne);
}
public function testAreObjectsEqual()
{
  $testTwo = new Testable();
  $this->_testable->resetMe = false;
  $this->assertEquals($this->_testable,$testTwo);
}

?>
Thanks to the clear naming of the methods, most of the code above is fairly self-explanatory: you have access to methods such as assertGreaterThan, assertLessThan, assertGreaterThanOrEqual, assertLessThanOrEqual, and assertEquals. The first assertEquals call demonstrates how you can use a method from the class your testing to provide the values to test against. The second assertEquals call demonstrates a very interesting use of this assertion. Not only can it be used to compare numeric values, but it can compare other things too—like objects. See that testTwo object we created in the test? We’ve changed the resetMe property to false instead of true. The assertEquals takes a look at the objects as a whole to see if they match. Because of the changed resetMe value, these two objects don’t match, so the assertion fails. assertEquals also has a few other tricks up its sleeve: it can compare DOMDocument objects or arrays. For more details on how these comparisons work, check out the relevant section in the PHPUnit documentation.

Stringing You Along

In addition to the math-related methods PHPUnit comes with, there are also a few that are specifically for working with strings. Keep in mind, of course, that PHP itself comes with a wide array of string handling methods, all of which you can use in your tests. These PHPUnit assertions are just there to make writing your tests a little easier and cleaner. Let’s have a look at a few of them:
<?php
public function testStringEnding()
{
  $testString = $this->_testable->getTestString();
  $this->assertStringEndsWith('frood',$testString);
}

public function testStringStarts()
{
  $testString = $this->_testable->getTestString();
  $this->assertStringStartsWith('hoopy',$testString);
}

public function testEqualFileContents()
{
  $this->assertStringEqualsFile('/path/to/textfile.txt','foo');
}

public function testDoesStringMatchFormat()
{
  $testString = $this->_testable->getTestString();
  $this->assertStringMatchesFormat('%s',$testString);
}

public function testDoesStringFileFormat()
{
  $testString = $this->_testable->getTestString();
  $this->assertStringMatchesFormatFile('/path/to/textfie.txt','foo');
}

?>
As with the math methods, the naming of these assertions gives you a clear indication of what they do. The first and second methods look at the string and see if it either starts with or ends with the given string. assertStringEqualsFile is a little more interesting: it examines the file you give it and tests to see if its contents are equal to a given string. This saves you the hassle of having to call file_get_contents to grab the data and check it yourself. In the above example, the test would pass if you had a file in the given path containing the string "foo". The next two methods, assertStringMatchesFormat and assertStringMatchesFormatFile, allow you to be a little more fine-grained in your matching technique. They let you define patterns to match against, using a set of placeholders you can find on the PHPUnit site. This way, you can verify if your values conform to a given format, which you can either provide as a string or as a file.

More of the Same?

Now let’s look at two other handy assertions that seem to constantly come in handy for me in my testing: assertNull and assertSame. They both do pretty much what their names describe, but here’s an example to cement the idea in your head.
<?php

public function testStringIsNotNull()
{
  $notANull = “i'm not a null!”;
  $this->assertNull($notANull);
}
public function testStringIsSame()
{
  $numberAsString = '1234';
  $this->assertSame(1234,$numberAsString);
}

?>
The first assertion in our above test is going to fail. It’s checking to see if the value in $notANull
is NULL, but it’s a string. The advantage to assertNull is that in cases like this it will be more clear and readable than trying to accomplish the same check with assertTrue or assertFalse. Now for assertSame. As you probably know, PHP is loosely typed, so it will consider the number 1234 and the string "1234" to be equal. As a result, assertEquals(1234, "1234") will pass. However, being a conscientious coder, you’re being very careful with your data types and want to ensure that a given variable exactly matches another, both in contents and in type. Well, you’re in luck, because that’s exactly what assertSame does. Because of this, the assertion in the example above will fail, as 1234 isn’t the same as "1234".

A Mixed Bag

I’m going to touch on a few of the less common assertions available in PHPUnit. While you probably won’t use them in every test you write, they can be tremendously handy when you do need them:
<?php

public function testArrayKeyExists()
{
	$this->assertArrayHasKey('first key',$this->_testable->testArray);
}
public function testAttributeExists()
{
	$this->assertClassHasAttribute('resetMe',get_class($this->_testable));
}
public function testFileIsReal()
{
	$this->assertFileExists('/path/to/file.txt');
}
public function testIsInstance()
{
	$this->assertInstanceOf('OtherClass',$this->_testable);
}

?>
I’ve introduced four new assertions here covering a wide range of features—array keys, class atributes, file existence, and object type. Let’s take them one at a time and get a feel for what they do. The first assertion simply checks the array from our sample class to see if "first key" is a valid array key for it. We’ve given our Testable class an array with that key, so this test passes with flying colors. Next, thanks to the assertClassHasAttribute method, we can check to see if our class has a given property. Again, this assertion happily passes because our test class has the resetMe property. Take note, though, that this is not to check if a property exists on a given object, only to see if its defined in a class. assertFileExists is another easy one—it just looks on the local file system to see if the file’s there. This follows the same rules as the PHP file system methods—if you can’t access it, the assertion will fail. Lastly, there’s assertInstanceOf, a shortcut method to tell if the object you’re working with is an instance of a given class. Of course, this is no different from assertTrue($this->_testable instanceof OtherClass), but it’s more concise and easier to read. For the final assertion in this article, we’ll look at one of the most flexible:
<?php

public function testDoesMatchRegex()
{
  $testString = $this->_testable->getTestString();
  $this->assertRegExp('/[a-z]+/',$testString);
}

?>
This is a simple example (I’m sure you’ve seen some monster regular expressions in your time) but it gets the point across.

In Conclusion

I’ve tried to list out most of the more useful assertions in this second article so you can have a better idea of what’s out there before you start testing. There’s always more than one way to do things, but these built-in assertions can save you a lot of time and hassle. Remember, the point to writing tests for your application isn’t just to say that you have, or to reach 100% code coverage. Writing good tests allows you to work on your code free of the fear that you might introduce new bugs (or reintroduce old ones). Ultimately, better tests will make for better code.

Frequently Asked Questions about PHPUnit Assertions

What are the different types of assertions in PHPUnit?

PHPUnit provides a variety of assertions that can be used to test your code. These include assertEquals, assertSame, assertContains, assertInstanceOf, and many more. Each of these assertions serves a different purpose. For example, assertEquals checks if two values are equal, while assertInstanceOf checks if an object is an instance of a specific class. Understanding these different assertions and when to use them is crucial for effective testing in PHPUnit.

How do I use the assertEquals function in PHPUnit?

The assertEquals function is used to check if two values are equal. It takes two parameters: the expected value and the actual value. If the two values are equal, the test passes; otherwise, it fails. Here’s an example of how to use assertEquals:

public function testEquality() {
$this->assertEquals(1, 1);
}
In this example, the test will pass because 1 is equal to 1.

What is the difference between assertEquals and assertSame in PHPUnit?

While both assertEquals and assertSame are used to compare two values, they work in slightly different ways. assertEquals checks if the two values are equal, while assertSame checks if they are the same. This means that assertEquals will pass if the two values are equal after type juggling, while assertSame will only pass if the two values are of the same type and value.

How can I use the assertContains function in PHPUnit?

The assertContains function is used to check if a specific value is present in an array or a string. It takes two parameters: the value to look for and the array or string to search in. If the value is found, the test passes; otherwise, it fails. Here’s an example of how to use assertContains:

public function testContainment() {
$this->assertContains('foo', array('foo', 'bar'));
}
In this example, the test will pass because ‘foo’ is found in the array.

What is the purpose of the assertInstanceOf function in PHPUnit?

The assertInstanceOf function is used to check if an object is an instance of a specific class. It takes two parameters: the name of the class and the object to check. If the object is an instance of the class, the test passes; otherwise, it fails. Here’s an example of how to use assertInstanceOf:

public function testInstance() {
$this->assertInstanceOf('MyClass', new MyClass());
}
In this example, the test will pass because the object is an instance of MyClass.

How can I use the assertStringMatchesFormat function in PHPUnit?

The assertStringMatchesFormat function is used to check if a string matches a specific format. It takes two parameters: the expected format and the string to check. If the string matches the format, the test passes; otherwise, it fails. Here’s an example of how to use assertStringMatchesFormat:

public function testStringFormat() {
$this->assertStringMatchesFormat('%s', 'foo');
}
In this example, the test will pass because ‘foo’ matches the format ‘%s’, which represents any string.

What is the purpose of the assertCount function in PHPUnit?

The assertCount function is used to check the number of elements in an array or a Countable object. It takes two parameters: the expected count and the array or Countable object to check. If the count matches the expected count, the test passes; otherwise, it fails. Here’s an example of how to use assertCount:

public function testCount() {
$this->assertCount(2, array('foo', 'bar'));
}
In this example, the test will pass because the array has 2 elements.

How can I use the assertTrue function in PHPUnit?

The assertTrue function is used to check if a value is true. It takes one parameter: the value to check. If the value is true, the test passes; otherwise, it fails. Here’s an example of how to use assertTrue:

public function testTrue() {
$this->assertTrue(true);
}
In this example, the test will pass because the value is true.

What is the difference between assertEmpty and assertNotNull in PHPUnit?

assertEmpty checks if a value is empty, while assertNotNull checks if a value is not null. A value is considered empty if it is null, false, an empty array, or an empty string. assertNotNull, on the other hand, will pass if the value is anything other than null.

How can I use the assertArrayHasKey function in PHPUnit?

The assertArrayHasKey function is used to check if an array has a specific key. It takes two parameters: the key to look for and the array to check. If the key is found in the array, the test passes; otherwise, it fails. Here’s an example of how to use assertArrayHasKey:

public function testArrayKey() {
$this->assertArrayHasKey('foo', array('foo' => 'bar'));
}
In this example, the test will pass because ‘foo’ is a key in the array.

Chris CornuttChris Cornutt
View Author

Chris has been involved with PHP and its community for about eight years now, most of that running his site, PHPDeveloper.org - a site devoted to bringing the most up-to-date, informative news and community happenings to the forefront and, more recently, Joind.in, a community conference feedback service. He’s a co-organizer of his local PHP user group(DallasPHP), a Zend Certified Engineer and currently works developing web applications and APIs for a large hosting company in Dallas, Tx.

PHP
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week