# Simplify Your Tests With Custom Assertions

Did you ever have to write tests with quiet complex assertions? I mean when you need to perform some calculations to decide if actual value is ok. If so, you obviously thought that your test is looking kinda weird and heavy.

But there is a way to significantly improve readability of all tests, even the most complex and ugly ones.

### Example problem

There is a bunch of algorithms, when you can not create example-based test, i.e. any algorithm using random generation. Our example will be about randomization too.

We have a randomly generated Basket of Balls. The Basket MUST meet the following conditions:

• It must contain `\$length` of balls;
• Every Ball must have unique number. So, there can be only one ball with given number in a Basket;
• Every Ball in a Basket must have a number within a given range, defined by `\$min` and `\$max` values.

The problem is, we cannot create any example-based test, because of random balls generation. There is another way: we execute test’s action (Basket generation) and check if those properties are met by actual result. We need to repeat this test sometimes to avoid lucky variations. This approach to testing is called property-based testing.

Let’s have a look on a test:

```<?php //tests/BasketGeneratorTest.php
{
/** @var  array */
private \$config;

/** @var  int */
private \$length;

private \$generator;

protected function setUp()
{
parent::setUp();

\$this->config = ['min' => 1, 'max' => 999];
\$this->length = 10;
}

public function testGenerator()
{

\$this->assertTrue(
\$ball->getNumber() <= \$this->config['max'] && \$ball->getNumber() >= \$this->config['min'],
\$message
);
}

for (\$i = 0; \$i < \$this->length; \$i++) {
for (\$j = \$i + 1; \$j < \$this->length; \$j++) {
if (\$balls[\$i]->equals(\$balls[\$j])) {
throw new \PHPUnit_Framework_AssertionFailedError(\$message);
}
}
}
}
}
```

On the following code snippets I wont’ include class definition and setUp() function to save a bit of place.

What we can say about this test at first sight? Assertions are very hard to understand. We need to read the whole block of code to understand what is actually checked by this test. Fortunately, there are plenty of ways to hide this complexity into easy-to-read assertions.

### Naive Approach

The first idea is pretty simple: just define an assert function inside the test case:

```<?php //tests/BasketGenerator.php
public function testGenerator()
{

}

{
/** @var Ball \$ball */
\$this->assertTrue(
\$ball->getNumber() <= \$this->config['max'] && \$ball->getNumber() >= \$this->config['min'],
\$message
);
}
}

{

for (\$i = 0; \$i < \$this->length; \$i++) {
for (\$j = \$i + 1; \$j < \$this->length; \$j++) {
if (\$balls[\$i]->equals(\$balls[\$j])) {
throw new \PHPUnit_Framework_AssertionFailedError(\$message);
}
}
}
}
```

This approach improves test readability a lot, but you cannot reuse your custom assertions in other tests. If you need this, you may go further and convert these assertions to constraints.

### Reusing Custom Assertions

Let’s extract the assertion to a separate class. PHPUnit has a mechanism of `Constraint`s for this. You create a `Constraint` and assert that a value matches this `Constraint`.

```<?php // tests/Constraint/UniqueBalls.php
namespace Constraint;

class UniqueBalls extends \PHPUnit_Framework_Constraint {
/**
* This function must return true if given value matches the constraint
* @param Ball[] \$balls
* @return boolean
*/
public function matches (\$balls) {
\$length = count(\$balls);
for (\$i = 0; \$i < \$length; \$i++) {
for (\$j = \$i + 1; \$j < \$length; \$j++) {
if (\$balls[\$i]->equals(\$balls[\$j])) {
return false;
}
}
}

return true;
}
}
```

Then you have two options: to use the constraint directly in `assertThat` call or create a base test class with assertion functions:

#### assertThat example

```<?php // tests/BasketGeneratorTest.php
public function testGenerator()
{

}
```

#### Base test case

```<?php // tests/BaseTestCase.php
class BaseTestCase extends \PHPUnit_Framework_TestCase
{
public static function assertUniqueBalls(array \$balls, \$message = '') {
}
}
```
```<?php // tests/BasketGenerator.php