TestCase

Assertions may follow one by one in simple tests. But sometimes it is useful to enclose the assertions to test class and structure them in this way.

The class must be descendant of Tester\TestCase and we talk about it simply as about testcase.

use Tester\Assert;

class RectangleTest extends Tester\TestCase
{
	public function testOne()
	{
		Assert::same(/* ... */);
	}

	public function testTwo()
	{
		Assert::match(/* ... */);
	}
}

# Run testing methods
(new RectangleTest)->run();

We can enrich a testcase by setUp() and tearDown() methods. They are called before/after every testing method:

use Tester\Assert;

class NextTest extends Tester\TestCase
{
	public function setUp()
	{
		# Preparation
	}

	public function tearDown()
	{
		# Clean-up
	}

	public function testOne()
	{
		Assert::same(/* ... */);
	}

	public function testTwo()
	{
		Assert::match(/* ... */);
	}
}

# Run testing methods
(new NextTest)->run();

/*


Method Calls Order
------------------
setUp()
testOne()
tearDown()

setUp()
testTwo()
tearDown()
*/

If error occurs in a setUp() or tearDown() phase, test will fail. If error occurs in the testing method, the tearDown() method is called anyway, but with suppressed errors in it.

We recommend that you write the annotation @testCase at the beginning of the test, then the command-line test runner will run the individual testcase methods in separate processes and in parallel in multiple threads. This can significantly speed up the entire testing process.

<?php
/** @testCase */

Annotation of Methods

There are a few annotations available to help us with testing methods. We write them toward the testing method.

@throws

It is equal usage of Assert::exception() inside a testing method. But notation is more readable:

/**
 * @throws RuntimeException
 */
public function testOne()
{
	// ...
}


/**
 * @throws LogicException  Wrong argument order
 */
public function testTwo()
{
	// ...
}

@dataProvider

This annotation suits when we want to run the testing method multiple times but with different arguments. (Not to be confused with the annotation of the same name for files.)

As an argument we write method name which returns parameters for the testing method. The method must return an array or Traversable. Simple example:

public function getLoopArgs()
{
	return [
		[1, 2, 3],
		[4, 5, 6],
		[7, 8, 9],
	];
}


/**
 * @dataProvider getLoopArgs
 */
public function testLoop($a, $b, $c)
{
	// ...
}

The other annotation @dataProvider variation accepts a path to INI file (relatively to test file) as an argument. The method is called so many times as the number of sections contained in INI file. File loop-args.ini:

[one]
a=1
b=2
c=3

[two]
a=4
b=5
c=6

[three]
a=7
b=8
c=9

and the method which uses the INI file:

/**
 * @dataProvider loop-args.ini
 */
public function testLoop($a, $b, $c)
{
	// ...
}

Similarly, we can pass path to a PHP script instead of INI. It must return array or Traversable. File loop-args.php:

return [
	['a' => 1, 'b' => 2, 'c' => 3],
	['a' => 4, 'b' => 5, 'c' => 6],
	['a' => 7, 'b' => 8, 'c' => 9],
];