How you test your code?
Tags: testing, phpunit, php, unittesting
Published: 2019-03-28 17:02:21

---
title: How you test your code?
published: true
description: UnitTest and Test Coverage with PHPUnit
tags: testing,phpunit,php,unittesting
---

![unit test](https://thepracticaldev.s3.amazonaws.com/i/p1zwh1fe58ubatubcqhq.jpg)

Testing code is one of the most important part to understand your application and behavior of code.Every developer knows how painful bugs can be, especially in the production stage as it takes hours of hard work. Testing each scenario can be as good as believing yourself. You write and execute your code, without knowing how it behaves if some exception occurs or some validation violates, this may cause a problem in staging or production. So, running test case plays a vital role in SDLC. You give rich life  and believe your code with eye closed, once your test coverage is at good level.


Today, we are going to write a simple test methods and run test code using tools like Xdebug and PHPUnit. PHPUnit is a programmer-oriented testing framework. This is the outstanding testing framework for writing Unit tests for PHP Web Applications. With the help of PHPUnit, we can direct test-driven improvement.


Let's install PHPUnit:

```
wget https://phar.phpunit.de/phpunit-7.5.phar
chmod +x phpunit-7.5.phar
sudo mv phpunit-7.5.phar /usr/bin/phpunit
``` 

There are several other way to insall phpunit. __Find more here__:[phpunit](https://phpunit.readthedocs.io/en/8.0/installation.html).


Now, To get our Test Coverage full report we need to install Xdebug: 

```
sudo apt install php-pear
pecl install xdebug
sudo apt-get install php-xdebug
```
Find More about __Xdebug__ here: [xdebug](https://xdebug.org/docs/install).


Without making further delay Let's dive into our simple test scenarios where we test whether an array is empty:

Create a folder __UnitTest__ where we will include all testable files. In this folder, create a subfolder  __tests__. Create a new file `phpunit.xml` in this subfolder and add following code.

{% gist https://gist.github.com/samsha1/b68e484501f06910705657d593df46ba %}

The `colors=”true”` will show the results in highlighted colors and `<directory>./UnitTestFiles/Test/</directory>` will ask PHPUnit for the location of the files to be tested. The filter tag is used while discovering GUI based report with statistics analysis of our test coverages. 


##Basic Conventions to Write Unit Test Case

Following are some basic conventions and steps for writing tests with PHPUnit:

1. Test File names should have a suffix Test. For example, if First.php needs to 
   be tested,the name of the test file name will be FirstTest.php
2. Similarly, If the class name is `MyFirstClass` than the test class name will be 
   `MyFirstClassTest`.
3. Add test as the prefix for method names. For example, if the method name is 
   __getuser()__, then in test class, it will become __testgetuser()__. You can 
   also use @test annotation in document block to declare it as a testing method.
4. All testing methods are `public`
5. MyFirstClassTest class should be inherited from __PHPUnit\Framework\TestCase__.


These are the major ground rules for the PHP unit testing framework. The essential configurations and settings are all setup. It is now time to write the first test case.

##Writing The First Unit Test Case in PHP

Create a file EmptyTest.php in UnitTest/tests. Add the following code to it.

{% gist https://gist.github.com/samsha1/eaf540908403d3ddbfa5dff1b12a5343 %}

Now, to run our test code inside terminal type: _phpunit <filename>_ i.e. phpunit tests/EmptyTest.php. 

Note: By running only phpunit, it defaults executes all test file inside UnitTest/tests directory because we have mentioned this directory in phpunit.xml above.

We will get our test failure because the value inside array is not empty. In my terminal I am getting: 

```
F                                                                   1 / 1 (100%)

Time: 513 ms, Memory: 10.00MB

There was 1 failure:

1) EmptyTest::testFailure
Failed asserting that an array is empty.

/home/samrat/myproj/testcase/tests/EmptyTest.php:8

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
```

Let's pass our above test case and add one more scenario to test equals.

{% gist https://gist.github.com/samsha1/06a464f6a04643cf672dbaf661f22bcd %}

{% gist https://gist.github.com/samsha1/da3e62afb4c5b4d3b9e984847492482d %}

It gives an error when $expected is not equal to $actual. If $expected equals $actual then it returns true. Remember, the first argument is _expected_ and the other is _actual_. The above test only passes if expected (0) is equal to (1). To pass above test case just replace 0 with 1 or 1 with 0. Now, run both testcase.

Our both test must pass:

```
PHPUnit 7.5.6 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.3.1-1+ubuntu18.04.1+deb.sury.org+1 with Xdebug 2.7.0
Configuration: /home/samrat/myproj/UnitTest/phpunit.xml

..                                                                  2 / 2 (100%)

Time: 200 ms, Memory: 10.00MB

OK (2 tests, 2 assertions)
```

You can find more about assertion here: [PHPUnit Assertion](https://phpunit.de/manual/6.5/en/appendixes.assertions.html)


Let’s look at another example in which a developer has created a code to parse the items received in json and validate it for the possible use case may be exception or for other validation rules.

Let's create _app/item_parser.php_ file inside UnitTest directory

{% gist https://gist.github.com/samsha1/a56f630f0c9d5aaedefcc70beeca882a %}

I've created a class called ItemsParser with static method called parse that takes one argument called response, received from json data. We have checked for different exceptions and returned parsed data as an array.

Let's add some exceptions class for above use cases inside same directory:

{% gist https://gist.github.com/samsha1/7a90618287d8b9897a6d90296a1b0fc7 %}


Now in the UnitTest/tests folder, create a new file called ItemsParserTest.php and add the following test code:

{% gist https://gist.github.com/samsha1/afb9bdb9910f1e0c0a6bbdb150c8fba8 %}

Run above test case, Our test case must pass. By, this we can assure ItemParser class is successfully instantiated.

As, we don't invoke real endpoint. Let's create a fake json data called one.json inside _UnitTest/json_ and test with it.

{% gist https://gist.github.com/samsha1/40fe792fc7a81e90c27958276ed5d9d6 %}

Now Let's write another test method to ensure our data is actually parsed the way we expected it:

{% gist https://gist.github.com/samsha1/43ca693180b993f2860fe4a8ab9f41d0 %}

As, we created fake data, and send that data to _ItemParser::parse()_ method. If we now run our test case we get the data as the way we expected.

```
PHPUnit 7.5.8 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.2.15-0ubuntu0.18.04.1 with Xdebug 2.6.0
Configuration: /home/samrat/myproj/UnitTest/phpunit.xml

..                                                                  2 / 2 (100%)

Time: 377 ms, Memory: 10.00 MB

OK (2 tests, 2 assertions)
```

Actually, what we did is we send json data and decoupled it on our data only with label and value as key and returned only data that is required as an array.

Now, Let's test for the array keys we are getting:

{% gist https://gist.github.com/samsha1/4eda2b7bc37ea043d8d4f7746bb53c2d %}

From above code we can ensure that whether we are getting the key we expected i.e label and value.

What about the exceptions we added to our methods, whether they are working the way we wanted? Well I am not sure so let's test it.

Say, we have some json data with price in string:

{% gist https://gist.github.com/samsha1/50a9828e4ddb23a7c4b6bf4e5452beb5 %}

 
How our code block response when we send price as string, well we must be sure our code handles such kind of exceptions.

{% gist https://gist.github.com/samsha1/390ad8a0d9dac1a7d4223a959c4e67a1 %}

expectException() method is to ensure whether expected exception is thrown by our code block. Run phpunit and check above code it must by the way!

Revise, the ItemParser.php file we have used number_format function to convert cent price into dollar.So, Let's write test to check whether our price has been successfully converted.

{% gist https://gist.github.com/samsha1/4781c09d2b09a8783a39ee7acc0e2c33 %}


And These test can go on and on, wouldn't it be nice to get report or analyzer for our test case. To get total test coverage report would be great. So, we have written some test code and let's generate our test report and find out how much code did we really covered?

It's simple just type this in terminal: phpunit  --coverage-html <directory to generate report>. _In my case phpunit  --coverage-html report/_. You will get whole report in html format. By the way, we can generate in xml, php, text and many other formats. Just type: phpunit --help for more.

![test coverage report](https://thepracticaldev.s3.amazonaws.com/i/0an4jimrmt4r7e9x7tib.png)

Above test coverage explains, our first example test coverage is 100% but ItemParserTest could be better and we only covered some part of our code so let's stick with 90%. I leave it up to you to make it 100%. Actually, 80% code coverage can be acceptable coverage in software world (heard somewhere).

We also get the report of where we can do better. Here's some other code coverage statistics:  

![coverage statistics](https://thepracticaldev.s3.amazonaws.com/i/rmzhtbbnu9bbl5cvk4en.png)

![Insufficent Coverage](https://thepracticaldev.s3.amazonaws.com/i/20zrtkjkcnmgc86ohsvx.png)


##Conclusion

This article explains a basic setup that help you in getting started with PHPUnit for PHP unit testing.

Hope you find this article helpful. Unit Testing is a vast topic. Here I have given you a brief introduction so that you can start writing your own tests. I would like to  mention several changes in the latest version of PHPUnit. In the previous versions, the class extend with `PHPUnit_Framework_TestCase`. In the latest version, it extends with `TestCase` only. Please comment below if you have any question or suggestions.

You are awesome!