TestCase
********
.[perex]
In simple tests, assertions can follow one after another. However, sometimes it's advantageous to wrap assertions in a test class to structure them.
The class must extend `Tester\TestCase`, and we refer to it simply as a **TestCase**. The class must contain test methods starting with `test`. These methods will be executed as tests:
```php
use Tester\Assert;
class RectangleTest extends Tester\TestCase
{
public function testOne()
{
Assert::same(/* ... */);
}
public function testTwo()
{
Assert::match(/* ... */);
}
}
# Run test methods
(new RectangleTest)->run();
```
A TestCase written this way can be further enhanced with `setUp()` and `tearDown()` methods. They are called before and after each test method, respectively:
```php
use Tester\Assert;
class NextTest extends Tester\TestCase
{
protected function setUp()
{
# Preparation
}
protected function tearDown()
{
# Clean-up
}
public function testOne()
{
Assert::same(/* ... */);
}
public function testTwo()
{
Assert::match(/* ... */);
}
}
# Run test methods
(new NextTest)->run();
/*
Method Call Order
-----------------
setUp()
testOne()
tearDown()
setUp()
testTwo()
tearDown()
*/
```
If an error occurs during the `setUp()` or `tearDown()` phase, the test will fail overall. If an error occurs in the test method itself, the `tearDown()` method is still executed, but any errors within it are suppressed.
Within a test method, you can skip the current test at any time by calling `$this->skip('reason')`, for example when a prerequisite is not met.
We recommend writing the [@testCase |test-annotations#testCase] annotation at the beginning of the test file. The command-line test runner will then execute the individual TestCase methods in separate processes and in parallel using multiple threads. This can significantly speed up the entire testing process.
/--php
<?php
/** @testCase */
\--
Method Annotations
==================
Several annotations are available for test methods to facilitate testing. Write them above the test method.
Since version 2.7, you can also write them as PHP attributes from the `Tester\Attributes` namespace. They work exactly like the annotations, but your IDE completes them and checks the class names you use in them. If a method has both, the attribute applies. The examples below show the attribute first and then the same thing as an annotation. .{data-version:2.7.0}
@throws .[filter]
-----------------
It is equivalent to using `Assert::exception()` inside the test method, but the notation is clearer:
```php
use Tester\Attributes\Throws;
#[Throws(RuntimeException::class)]
public function testOne()
{
// ...
}
#[Throws(LogicException::class, 'Wrong argument order')]
public function testTwo()
{
// ...
}
```
The optional second argument is a pattern that the exception message must match, just like in [Assert::exception() |assertions#Assert::exception]. Instead of an exception class, the attribute also accepts an `E_*` constant, so the test can expect a PHP error, for example a warning: `#[Throws(E_WARNING)]`.
The same written as annotations:
```php
/**
* @throws RuntimeException
*/
public function testOne()
{
// ...
}
/**
* @throws LogicException Wrong argument order
*/
public function testTwo()
{
// ...
}
```
@dataProvider .[filter]
-----------------------
This annotation is useful when you want to run the test method multiple times with different parameters. (Do not confuse it with the annotation of the same name for [test files |test-annotations#dataProvider].)
After it, specify the name of a method that returns the arguments for the test method. This method must return an array or a Traversable object. A simple example:
```php
use Tester\Attributes\DataProvider;
public function getLoopArgs()
{
return [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
}
#[DataProvider('getLoopArgs')]
public function testLoop($a, $b, $c)
{
// ...
}
```
The same written as an annotation:
```php
/**
* @dataProvider getLoopArgs
*/
public function testLoop($a, $b, $c)
{
// ...
}
```
If the provider returns no data sets at all, the test fails. An empty provider is almost always a mistake, such as an empty file or a filter that matches nothing, and a test method that silently didn't run would look as if it had passed. .{data-version:2.7.0}
The second variation of the **@dataProvider** annotation accepts a path to an INI file (relative to the test file) as a parameter. The method is called as many times as there are sections in the INI file. File `loop-args.ini`:
```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 that uses the INI file:
```php
#[DataProvider('loop-args.ini')]
public function testLoop($a, $b, $c)
{
// ...
}
```
As an annotation, write `@dataProvider loop-args.ini`.
Similarly, instead of an INI file, you can reference a PHP script. It must return an array or a Traversable object. File `loop-args.php`:
```php
return [
['a' => 1, 'b' => 2, 'c' => 3],
['a' => 4, 'b' => 5, 'c' => 6],
['a' => 7, 'b' => 8, 'c' => 9],
];
```
As with the [data provider for test files |test-annotations#dataProvider], you can append a filtering query after the file name to run the method only for the matching sections. With the attribute, pass the query as the second argument, for example `#[DataProvider('loop-args.ini', 'one')]`.
A method can also have several data providers, written as several attributes or annotations. It then runs with the data sets of all of them, one after another.
{{maintitle: Nette Tester TestCase: Organize PHP Tests in Classes}}
{{description: Wrap assertions in a test class to give them structure: test methods, setUp and tearDown, expected exceptions and data providers in method annotations.}}
TestCase
In simple tests, assertions can follow one after another. However, sometimes it's advantageous to wrap
assertions in a test class to structure them.
The class must extend Tester\TestCase, and we refer to it simply as a TestCase. The class must contain test
methods starting with test. These methods will be executed as tests:
use Tester\Assert;
class RectangleTest extends Tester\TestCase
{
public function testOne()
{
Assert::same(/* ... */);
}
public function testTwo()
{
Assert::match(/* ... */);
}
}
# Run test methods
(new RectangleTest)->run();
A TestCase written this way can be further enhanced with setUp() and tearDown() methods. They are
called before and after each test method, respectively:
use Tester\Assert;
class NextTest extends Tester\TestCase
{
protected function setUp()
{
# Preparation
}
protected function tearDown()
{
# Clean-up
}
public function testOne()
{
Assert::same(/* ... */);
}
public function testTwo()
{
Assert::match(/* ... */);
}
}
# Run test methods
(new NextTest)->run();
/*
Method Call Order
-----------------
setUp()
testOne()
tearDown()
setUp()
testTwo()
tearDown()
*/
If an error occurs during the setUp() or tearDown() phase, the test will fail overall. If an error
occurs in the test method itself, the tearDown() method is still executed, but any errors within it are
suppressed.
Within a test method, you can skip the current test at any time by calling $this->skip('reason'), for example
when a prerequisite is not met.
We recommend writing the @testCase annotation at the
beginning of the test file. The command-line test runner will then execute the individual TestCase methods in separate processes
and in parallel using multiple threads. This can significantly speed up the entire testing process.
<?php
/** @testCase */
Method Annotations
Several annotations are available for test methods to facilitate testing. Write them above the test method.
Since version 2.7, you can also write them as PHP attributes from the Tester\Attributes
namespace. They work exactly like the annotations, but your IDE completes them and checks the class names you use in them. If a
method has both, the attribute applies. The examples below show the attribute first and then the same thing as an annotation.
@throws
It is equivalent to using Assert::exception() inside the test method, but the notation is clearer:
use Tester\Attributes\Throws;
#[Throws(RuntimeException::class)]
public function testOne()
{
// ...
}
#[Throws(LogicException::class, 'Wrong argument order')]
public function testTwo()
{
// ...
}
The optional second argument is a pattern that the exception message must match, just like in Assert::exception(). Instead of an exception class, the
attribute also accepts an E_* constant, so the test can expect a PHP error, for example a warning:
#[Throws(E_WARNING)].
The same written as annotations:
/**
* @throws RuntimeException
*/
public function testOne()
{
// ...
}
/**
* @throws LogicException Wrong argument order
*/
public function testTwo()
{
// ...
}
@dataProvider
This annotation is useful when you want to run the test method multiple times with different parameters. (Do not confuse it
with the annotation of the same name for test
files.)
After it, specify the name of a method that returns the arguments for the test method. This method must return an array or a
Traversable object. A simple example:
use Tester\Attributes\DataProvider;
public function getLoopArgs()
{
return [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
}
#[DataProvider('getLoopArgs')]
public function testLoop($a, $b, $c)
{
// ...
}
The same written as an annotation:
/**
* @dataProvider getLoopArgs
*/
public function testLoop($a, $b, $c)
{
// ...
}
If the provider returns no data sets at all, the test fails. An empty provider is almost always a mistake,
such as an empty file or a filter that matches nothing, and a test method that silently didn't run would look as if it had
passed.
The second variation of the @dataProvider annotation accepts a path to an INI file (relative to the test file) as a
parameter. The method is called as many times as there are sections in the 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 that uses the INI file:
#[DataProvider('loop-args.ini')]
public function testLoop($a, $b, $c)
{
// ...
}
As an annotation, write @dataProvider loop-args.ini.
Similarly, instead of an INI file, you can reference a PHP script. It must return an array or a Traversable object. File
loop-args.php:
return [
['a' => 1, 'b' => 2, 'c' => 3],
['a' => 4, 'b' => 5, 'c' => 6],
['a' => 7, 'b' => 8, 'c' => 9],
];
As with the data provider for test files, you can
append a filtering query after the file name to run the method only for the matching sections. With the attribute, pass the query
as the second argument, for example #[DataProvider('loop-args.ini', 'one')].
A method can also have several data providers, written as several attributes or annotations. It then runs with the data sets
of all of them, one after another.