Unit Testing in Drupal 8
Unit testing is a method of testing individual units of code. A unit can be defined as the smallest testable part of an application. Unit tests are short code fragments created during the development process. Unit testing verifies the behavior of a piece of code in isolation i.e., independent of its normal application context. A unit code can be as small as a class or even just a method.
Each test case is run independently from others and can use substitutes such as mock objects to assist testing a module in isolation. Unit tests are written and run to ensure that code behaves as intended before integration testing begins. Unit tests are a step prior to integration tests, not a replacement for them.
Benefits of Unit Testing
Unit tests are primarily written as a good practice to help developers identify and fix bugs, to refactor code, and to serve as documentation for a unit of software under test. To achieve these benefits, unit tests ideally should cover all the possible paths in a program. One unit test usually covers one specific path in one function or method.
Benefits of unit testing include:
Unit testing is blazing fast to run. There are more than 1000 unit test cases written for Drupal 8 core modules and the tests come with the Drupal core package. It takes only six seconds to run them all.
Unit testing can act as documentation for your code. When you look at the unit test written for a particular method, it gives a very clear understanding of what that method is about and how it is meant to be used.
Unit testing can make refactoring the code easier. If you have unit tests written, you can run the test to make sure nothing is breaking as you make changes. You will also be able to know what the impact of a change on that unit will be.
Unit testing provides constant feedback as you are writing and testing code.
Reduce Bugs During Integration Testing
During integration testing, it can become difficult to know what module or piece of code is causing a bug. As a result, one ends up spending lot of time in debugging. If each unit is properly tested it will reduce a considerable number of bugs in integration testing.
Different Ways of Unit Testing
Unit testing can be done manually or automatically.
Manual Unit Testing
This mode of testing does not use an automated framework like Jenkins, Selenium, etc. for running tests. Testing is done manually on the web browser by actually going in and clicking around to make sure the module is working correctly. This includes certain GUI or stress tests. This is a bit time consuming as all the steps need to be performed manually and sometimes documented, which can be extra overhead.
Automated Unit Testing
Automatic unit testing can be done by a variety of programs. Some of the most commonly used are SimpleTest and PHPUnit. SimpleTest is a PHP unit test and web test framework. PHPUnit comes with Drupal 8 core and is the standard unit testing framework for PHP. Because it ships with Drupal 8, you don’t have to install it separately and you can trust that it is actively maintained. PHPUnit integrates with many PHP IDEs, including PhpStorm. It also supports mocks, often called test doubles or substitutes.
Running Unit Tests in Drupal 8 with PHPUnit
With PHPUnit, you can run a full unit test, a group of tests or one specific test using the commands below. You can run the tests either through terminal or IDE.
Running tests through Terminal
- 1. Run all PHP Unit Tests:
- 2. Run one specific group of tests:
../vendor/bin/phpunit --group Groupname
- 3. Run multiple groups of tests:
../vendor/bin/phpunit --group Group1,Group2
- 4. Run a specific test:
- Configure the IDE with the steps above and run the commands from the IDE.
Using Annotations in PHPUnit
Annotations allow us to tell PHPUnit how certain things are meant to be used. They can include:
- @covers: specifies that a given test “covers” a segment of code
- @depends: indicates that a given test is dependent on another test
- @dataProvider: indicates a data provider method
- @expectedException: tells PHPUnit that a known exception should pass the test
Using Mocks in PHPUnit
Mocks are objects pre-programmed with expectations which form a specification of the calls they are expected to receive. Every test method is not necessarily an encapsulated, independent entity. Often there are implicit dependencies between test methods hidden in the implementation scenario of a test.
If a class with similar situation needs to be unit tested then it should provide the input that it would require from the dependent class to execute the test. This is achieved by creating a mock object of the dependee class and providing it to the dependent class. For example:
$my_mock = $this->getMock(‘SomeInterface’);
Why Unit Test?
Simply put, a unit tested code is a better code. Unit tests are extremely fast, simple, fun to write, and save you from a considerable amount of bugs and additional work during the integration testing stage.