PHPUnit: Making your own assertion

Callbacks, callbacks, constraint, callbacks

PHPUnit is a very complete testing suite, and with Mockery is even better. Most of the assertions are covered: data in arrays, strings inside strings, classes instances, and so on.

Even so, PHPUnit is not perfect, and for your project, you may need a “custom” assertion. For example, I just stumbled upon the need to create a simple assertion to check if a class extending other contains a given variable set of methods.

There is no assertMethodExists for PHPUnit, so you may want to use assertTrue() and method_exists().

This will suffice, but there is another, more elegant way: creating your own.

Base assertions

The way most assertions work in PHPUnit is relatively simple. The base PHPUnit class, Assert, which is extended by TestCase, contains the assertThat() method. This method is called by other assertions with the value, an “expectation” class, and the message to return when the expectation fail.

The expectation object is a class extending the Constraint. This allows to receive the value and do multiple checks on it, making assertion more flexible instead of hard coding comparisons.

As you are already guessing, we can create our own Constraint, but there is mostly not need to do it. There are already some constraints like IsTrue, IsEmpty, and many others, that are easily created using the method of the same name.

Using an existing Constraint

What I’m looking for is to check if method_exists returns true for a given class and method. I can borrow the IsTrue constraint, which doesn’t take any argument, to be compared with what the method returns.

The same thing can be achieved using assertTrue(), but to me this feels more declarative. But where not here for this simple thing.

Using a callback

Let’s make the assumption that I need to assert that a method has a return type for a given class. Instead of creating a class that extends Constraint, we can use the Callback constraint which will save us time.

This callback receives the value, which in this case is an object instance, and must return true or false.

For more complex scenarios, we may need to create a Constraint instance, but that’s when the scope of a callback is way below what we want to assert. You may want to use that approach of creating your own Constraint if you want to avoid having traits or classes full of callbacks.

Bonus tip: Failing

You may thing that a callback must return a boolean, and that you’re married to return whatever message assertThat has set in case the assertion fails. Luckily, that is not the case. You can use the fail() method to fail an assertion manually, even inside a callback.

Following the above example, let’s say we want to return a message saying that the method does not exist. No problem, we will induce fail() if the ReflectionMethod fails.

For extensively larger logic around assertion, don’t by shy and extend the Constraint class of PHPUnit with your own.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store