Solidify Fragile Tests

Joe • August 31, 2016

php testing

On my first week at the new job I was tasked to fix some tests that were logging data. While the fix was simple enough, by using `Psr\Log\NullLogger as Logger` instead of `Monolog\Logger` in the test, during the process I ran into another test that appeared quite fragile.

Fragile test:

Our `getFood()` method returns an array of all foods by type. Given that, we would expect to see types, such as fruit, meat, vegetables, in the resulting array. Assuming we have setup our test to contain fruit, we can expect to see something similar:

<?php

class GetFoodTest extends TestCase
{

    public function testEnsureGetFoodContainsFruit()
    {
        $food = $data_source->getFood();
        $fruit = [
            'orange',
            'apple',
            'pear',
        ];

        $this->assertArraySubset($fruit, $food);
    }
}

I wasn't familiar with `assertArraySubset()`, so I checked out the PHPUnit documentation for it.

assertArraySubset(array $subset, array $array[, bool $strict = '', string $message = ''])

Here’s what it says about it:

"Reports an error identified by $message if $array does not contains the $subset."

The problem with this test is that `assertArraySubset()` will fail if the items in the array are out of order. And since we Don't have an `ORDER BY` on our query in our data source we cannot guarantee the order of the returned data.

The solution I ended up going with was to change the assertion. I used `array_diff()` because I wanted to compute the difference of arrays.

Since the first argument is compared against the rest I did the assertion twice, to ensure both arrays were equal; the number of differences was 0. This solution allows the order of the data to not impact the success of failure of the test.

<?php

class GetFoodTest extends TestCase
{

    public function testEnsureGetFoodContainsFruit()
    {
        $food = $data_source->getFood();
        $fruit = [
            'orange',
            'apple',
            'pear',
        ];

        $this->assertEquals(0, count(array_diff($food, $fruit)));
        $this->assertEquals(0, count(array_diff($fruit, $food)));
    }
}

Hope this helps, happy testing. Thanks for reading.