Keep Calm and Write Test
In continuation with first post in series of three for the project “Framework Unit Testing”, in this one I will talk about unit testing specifically for php libraries. This post is mainly divided into two parts, one is for php unit testing and another on the project update. Feel free to skip any or all part(s).
Running tests on more than one version of PHP.
Setting up environment for testing is the foremost important task in the process of testing. We have already seen how to setup phpunit now we will see how setup system to run tests on different versions of php.
Tools needed to set this up are php-build[1] and phpenv[2]. Both can be downloaded from their git repository hosted at github either by cloning them or just downloading archive directly. Now use php-build to build a version of a php. You can get a list of all versions of php by using command `php-build --definitions`. Before continuing you should also install some basic build dependencies with your package manager. Using `sudo apt-get install build-essential autoconf automake libtool bison re2c` works on Debian based distros of linux.
To build version a.b.c you just need to run `php-build -i development a.b.c $HOME/.phpenv/versions/a.b.c`. This will download php a.b.c. from src and build it, this may take some minutes to complete, so be patient. Now you can use phpenv to enable php a.b.c version. Its command is `phpenv global a.b.c`. You can check current php version `php -v`. To revert back the active version to system’s default use `phpenv global system`.
Object Oriented Testing
Object oriented programming is centered around concepts like Object, Class, Message, Interfaces, Inheritance, Polymorphism etc. An object has state, behavior, and identity. The existence of state within an object means that the order in which operations are invoked is important and we can formally characterize the behavior of the object in terms of Finite State Machines (FSMs).
Traditional unit testing is concerned with testing units which are isolated from the surrounding program. The unit is normally the function or the module. However, for object-oriented programs the smallest unit is the class (or object). The attributes of a class cannot easily be separated from the operations due to the high level of coupling between the state and most of the operations. This does not mean that operations cannot be validated in isolation from each other, it means that the attributes of the classes must be present and accessible.
Writing test cases for a particular unit with respect to FSM is very simple. First the class is put into a particular state and then different operations are performed on it which may change the state to some another state. Now assertions are written to test the final state. Refer the following table while creating tests for a particular operation. Each method (function) of a class is an operation that could be applied to class present in a particular state.
Type |
Getter |
Setter |
Static |
Visibility |
|||
Public |
Test it. |
Test it |
Test it. |
Protected |
Test it. |
Test it |
Test it |
Private |
Don’t test it. |
Don’t test it. |
Don’t test it. |
Testing getter methods:
Using state based testing, first object is setted to a state (use reflection if needed) and then getter is invoked and tested on expected output. Example:
$field = new TextField;
TestHelper::setValue($field, 'id', 'myId');
TestHelper::setValue($field, 'name', 'myName');
TestHelper::setValue($field, 'value', 'avalue');
$this->assertEquals(
$field->input,
'<input type="text" name="myName" id="myId" value="avalue"/>'
);
Testing setter methods:
Using state based testing, pass input values to setter and then check the state achieved (use reflection if needed). Example:
$field = new \Joomla\Form\Field\TextField;
$this->assertEquals(
$field->type,
'Text'
);
$this->assertNull($field->formControl);
$this->assertNull(TestHelper::getValue($field, 'form'));
Using code coverage analysis as a tool
Code coverage analysis is a report which shows tested code and untested code. It can be used to find out sections of code that are unreachable or dead code. Program execution will never execute this section of code in any possible conditions.
Other use of code coverage analysis is to create boundary test cases. In a function which is purely an implementation of an algorithm it is not possible to think of every possible input-output scenarios. In cases like these code coverage can give a hint of missing conditions. To create a html report of coverage using phpunit you need a configured debugger (either Xdebugger[3] or Zend Debugger[4]). And by using command `phpunit --coverage-html ./report` we get a analysis report in report which is viewable in a browser. Report can also be exported in other formats like Clover XML, Crap4J XML, text, PHPUnit XML.
Project Update
The project to add and review tests of framework packages is half completed. I am going to show status of the project through some stats.
Though basic work is complete I am thinking about making another pass through all these packages for improving type of assertion used. Filesystem package is in the middle of transition to use vfsStream[5]. While writing tests I encountered with several bugs, deadcode and redundant code in different packages which I fixed right away. Archive, Database, Language, Image, Router, DI, Data and View packages are in pipeline.
References
- https://github.com/CHH/php-build
- https://github.com/phpenv/phpenv
- http://docs.joomla.org/Configuring_Xdebug_for_PHP_development
- http://www.zend.com/topics/Zend-Debugger-Installation-Guide.pdf
- https://github.com/mikey179/vfsStream
Some articles published on the Joomla Community Magazine represent the personal opinion or experience of the Author on the specific topic and might not be aligned to the official position of the Joomla Project
By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/
Comments