
#php
This article will further explain how to use PHPUnit tests. And annotations, test suits, and various framework methods.
In the previous article Introduction To Testing With PHPUnit - Part 1 we have explained how tests should be organized, in this article we will explain a little more about test suits and other useful options, methods, and commands of the PHPUnit framework.
First, let's tackle test suits...
Create a new file in the ./src folder named User.php and create a new folder and file in ./tests/user/UserTest. And after that register a new test suite for ./user in phpunit.xml, so it looks like this.
root/
-src/
Article.php
User.php
-tests/
-run/
ArticleTest.php
-user/
UserTest.php
-vendor
composer.json
composer.lock
phpunit.xml
<?php
namespace App\Model;
use Exception;
class User{
protected $name;
protected $session;
function __construct($name, $session){
$this->name = $name;
$this->session = $session;
}
function getName():string
{
return $this->name;
}
function getStatus():bool
{
if(!isset($this->session)){
throw new Exception("Session null.");
}
return $this->session;
}
function updateName():void
{
}
}
<?php
use PHPUnit\Framework\TestCase;
use App\Model\User;
class UserTest extends TestCase{
function testAddition()
{
$user = new User("Luka", true);
$this->assertInstanceOf(User::class, $user);
}
/**
* @test
* @dataProvider userData
*/
function testgetName($name, $status)
{
$this->assertSame($name, (new User($name, $status))->getName());
}
/**
* @test
* @dataProvider userData
*/
function testgetStatus($name, $status)
{
if(!isset($status)){
//confirms exception for Jane
$this->expectException(\Exception::class);
$this->expectExceptionMessage("Session null.", (new User($name, $status))->getStatus());
}else{
//confirms session exists for John
$this->assertTrue(true, (new User($name, $status))->getStatus());
}
}
//data provider
static function userData()
{
return [
['John Doe', true],
['Jane Doe', null]
];
}
/** @test */
function testupdateName()
{
//test we did not finished yet
$this->markTestIncomplete(
'This test has not been implemented yet.'
);
}
}
Adding a new test suite is quite simple from here on, we just need to add a new test suite directory statement in phpunit.xml...
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/|version|/phpunit.xsd"
bootstrap="./tests/bootstrap.php">
<testsuites>
<testsuite name="unit">
<directory>tests/run</directory>
</testsuite>
<testsuite name="user">
<directory>tests/user</directory>
</testsuite>
</testsuites>
</phpunit>
And now when we run ./vendor/bin/phpunit it will run both ./run and ./user test suites, so if we want to test just one test suite we can specify it with a command.
./vendor/bin/phpunit --testsuite user
But we still did not explain what are annotations and data providers, if you look up in UserTest.php code you may already notice that there are some weird comments above functions.
<?php
//...
/**
* @test
* @dataProvider userData
*/
function testgetName($name, $status)
{
$this->assertSame($name, (new User($name, $status))->getName());
}
//....
Those comments are our annotations, they are just metadata PHPUnit will use to make sense of our files. Here "@test" annotation is used to declare which methods are test methods to PHPUnit, sure test methods will run even without annotation if they respect naming conventions, but if we change the naming convention for some reason it will tell the framework to run even that method as a test, this metadata also helps out to organize test and made them more readable to other college programmers.
If you wonder what is "@dataProvider userData", this is our annotation that declares that the method under it should use data from the data provider method, in our case it is userData. You can inspect this method in UserTest class. This can save you time from writing repetitive code and make it easier to perform bulk testing to see how some component works under load.
There is also a way to evade testing tests we still did not finish with the markTestIncomplete method as you can see at the end of class. In addition, there are some useful test methods we can use in the framework:
assertEquals
assertTrue
assertFalse
assertNull
assertNotNull
assertSame
assertNotSame
expectException
assertCount
assertContains
And some useful terminal commands:
Run all tests.
phpunit
Run the selected method.
phpunit --filter testMethod
Runs the selected test suite.
phpunit --testsuite suiteName
Stop on the first test failure.
phpunit --stop-on-failure
Have fun testing.
[root@techtoapes]$ Author Luka
Login to comment.