Unit Test A Sorting Functionality using PHPUnit

In this post, I'm going to walk through a small code sample that automates unit testing for a sort functionality. We will call a JSON API URL, and then test that the information received is properly sorted. We'll also make the tests completely dynamic, enabling us to test multiple parameters to sort on. 

To start with, we'll need to define an array of $sortableValues that we can then loop through to test. By saving the values as a Key-Value store, we can test both the abbreviation (the string passed through the URL), and the value (which will be in the JSON response)

For example, a URL that sorts on price ascending will look something like this: 

http://localhost:8000/search?srt-pr-d

Meanwhile, within the JSON response we'll receive some data that looks like this: 

data { 
    name: Audi, 
    price: 10000,
    year: 2015, 
    score: 9 
}

So in order to deal with both the URL and the JSON, we store price within the associate array like this, where pr is the abbreviation and price is the value

 $sortableValues = array("price"=>"pr", "year"=>"yr", "score"=>"df");

Next, we'll want to loop through this array. We can instantiate a loop of an associate array in PHP like so: 

 foreach ($sortableValues as $value => $abbreviation) { 
    // do something 
}

The next thing we'll need to do is define a base variable, I'll call it $highestValue, to test our incoming values against. Each time our code goes through the loop, it will validate that the current price is less than $highestvalue, then replace this variable with the current value.

So if we are sorting on year, as we go through the loop $highestvalue will go from 9999999 to 2017 to 2016 to 2015, etc. 

foreach ($sortableValues as $value => $abbreviation) {
    $highestValue = 9999999;
}

Next we'll create an array of URLs in order to make sure our sorting functionality works across multiple pages. Within the URL, we will also add the $abbreviation, enabling the dynamic testing of each of our sortable values. 

 $urls = array('/search?&srt='.$abbreviation.'-d', '/search?page=2&srt='.$abbreviation.'-d');

After all that setup, we're finally ready to access some data! In order to make the test output readable, I add a brief comment before each URL is called. That way when something goes wrong it is easier to pinpoint the bug. 

We'll also access the URLs within a foreach loop, nesting our functionality and returning a variable named $vehicles full of our JSON data. 

foreach ($sortableValues as $value => $abbreviation) {
    $highestValue = 99999999;
    $urls = array('/search?&srt='.$abbreviation.'-d', '/search?page=2&srt='.$abbreviation.'-d');
    foreach ($urls as $url) {
        echo "\nAbout to test '".$url."'";
        $this->get($url);
        $_jsonresponse = json_decode($this->response->getContent(), true);
        $vehicles = ($_jsonresponse['data']);
            }
}

Finally, we have to perform the core functionality of the test. In human terms, we have to assert that the $value of each vehicle (where value is a price, year, or score), is less than the currently stored $highestvalue. Then we must re-assign $highestvalue to the current vehicle's value. 

In computer terms, that ends up looking like this: 

foreach ($vehicles as $vehicle) {
    $this->assertTrue($vehicle[$value] <= $highestValue);
    $highestValue = $vehicle[$value];
}

With this assertion complete, we can now go back to the top of the loop and run through every vehicle on the page, for every URL we have entered, for every sortable value. With 100 results on each page, this one function ends up testing 600 values! 

foreach ($sortableValues as $value => $abbreviation) {
    $highestValue = 99999999;
    $urls = array('/search?&srt='.$abbreviation.'-d', '/search?page=2&srt='.$abbreviation.'-d');
    foreach ($urls as $url) {
        echo "\nAbout to test '".$url."'";
        $this->get($url);
        $_jsonresponse = json_decode($this->response->getContent(), true);
        $vehicles = ($_jsonresponse['data']);
        foreach ($vehicles as $vehicle) {
            $this->assertTrue($vehicle[$value] <= $highestValue);
            $highestValue = $vehicle[$value];
        }
    }
}

Do you have any questions? Can you think of a better way to test this functionality? Let me know in the comments below!