Getting Started with Tester

Even good programmers make mistakes. The difference between a good programmer and a bad one is that the good one will do it only once and next time detect it using automated tests.

  • “One who doesn't test is doomed to repeat his or her own mistakes.” (wise proverb)
  • “When we get rid of one error, another one appears.” (Murphy's Law)
  • “Whenever you are tempted to print statement, write it as a test instead.” (Martin Fowler)

Have you ever written the following code in PHP?

$obj = new MyClass;
$result = $obj->process($input);

var_dump($result);

So, have you ever dumped a function call result just to check by eye that it returns what it should return? You surely do it many times per day. With hand on your heart, if everything works, do you delete this code and expect that the class will not be broken in the future? Murphy's Law guarantees the opposite :-)

In fact, you wrote the test. It needs slight modification to not require our inspection, simply to be able to check itself. And if you didn't delete it we could run it any time in the future to verify that everything still works as it should. You may create a large amount of these tests over time, so it would be nice if we were able to run them automatically.

And Nette Tester helps exactly with that.

What Makes Tester Unique?

Writing tests for Nette Tester is unique in that each test is a standard PHP script that can be run standalone.

So when you write a test, you can simply run it to see if there is a programming error. If it works properly. If not, you can easily step through program in your IDE and look for a bug. You can even open it in a browser.

And most importantly – by running it, you will perform the test. You will immediately find out if it passed or failed. How? Let's show up here. Let's write a trivial test for using PHP array and save it to the file ArrayTest.php:

<?php
use Tester\Assert;

require __DIR__ . '/vendor/autoload.php';  # load Composer autoloader
Tester\Environment::setup();               # initialization of Nette Tester

$stack = [];
Assert::same(0, count($stack));   # we expect count() to return zero

$stack[] = 'foo';
Assert::same(1, count($stack));   # we expect count() to return one
Assert::contains('foo', $stack);  # verify that the $stack contains the item 'foo'

As you can see, assertion methods such as Assert::same() are used to assert that an actual value matches an expected value.

The test is written, we can run it from command-line. The first run will reveal any syntax errors, and if you didn't make a typo, you will see:

$ php ArrayTest.php

OK

Try changing the statement to Assert::contains('XXX', $stack); in the test and watch what happens when run:

$ php ArrayTest.php

Failed: ['foo'] should contain 'XXX'

in ArrayTest.php(17) Assert::contains('XXX', $stack);

FAILURE

We continue about writing in the Writing Tests chapter.

Installation and Requirements

Minimal required PHP version by Tester is 7.1 (for more details, see the supported PHP versions table). The preferred way of installation is by Composer:

composer require --dev nette/tester

Try to run the Nette Tester from the command line (without any arguments it will only show a help summary):

vendor/bin/tester

Running Tests

As our application grows, a number of tests grows with it. It would not be practical to run tests one by one. Therefore, the Tester has a bulk test runner, which we invoke from the command line. The parameter is the directory in which the tests are located. The dot indicates the current directory.

vendor/bin/tester .

The Nette Tester runner searches the specified directory and all subdirectories and searches for tests, which are files *.phpt and *Test.php. It will also find our test ArrayTest.php, as it matches the mask.

Then it starts testing. It runs each test as a new PHP process, so it runs completely isolated from the others. It runs in parallel in multiple threads, making it extremely fast. And first runs tests that failed during the previous run, so you'll know right away if you fixed the error.

For each done test, the runner prints one character to indicate progress:

  • . – test passed
  • s – test has been skipped
  • F – test failed

The output can look like this:

 _____ ___  ___ _____ ___  ___
|_   _/ __)( __/_   _/ __)| _ )
  |_| \___ /___) |_| \___ |_|_\  v2.5.2

Note: No php.ini is used.
PHP 8.3.2 (cli) | php -n | 8 threads

........s................F.........

-- FAILED: greeting.phpt
   Failed: 'Hello John' should be
       ... 'Hello Peter'

   in greeting.phpt(19) Assert::same('Hello Peter', $o->say('John'));

FAILURES! (35 tests, 1 failures, 1 skipped, 1.7 seconds)

35 tests were run, one failed, one was skipped.

We continue in the Running tests chapter.

Watch Mode

Are you refactoring the code? Or do you even develop according to the TDD (Test Driven Development) methodology? Then you will like the watch mode. The Tester monitors the source codes and runs itself when changed.

During development, you have a terminal in the corner of the monitor, where the green status bar lights up on you, and when it suddenly turns red, you know that you just did do something unwanted. It's actually a great game where you program and try to stick to the color.

Watch mode is started using the parameter –watch.

CodeCoverage Reports

The Tester can generate reports with an overview of how much source code the tests cover. The report can be either in human readable HTML format or Clover XML for further machine processing.

See the sample HTML report with code coverage.

Supported PHP versions

version compatible with PHP
Tester 2.5 PHP 8.0 – 8.3
Tester 2.4 PHP 7.2 – 8.2
Tester 2.3 PHP 7.1 – 8.0
Tester 2.1 – 2.2 PHP 7.1 – 7.3
Tester 2.0 PHP 5.6 – 7.3
Tester 1.7 PHP 5.3 – 7.3 + HHVM 3.3+
Tester 1.6 PHP 5.3 – 7.0 + HHVM
Tester 1.3 – 1.5 PHP 5.3 – 5.6 + HHVM
Tester 0.9 – 1.2 PHP 5.3 – 5.6

Applies to the latest patch versions.

Till version 1.7 Tester supported HHVM 3.3.0 or newer (using tester -p hhvm). Support has been dropped since Tester 2.0. Usage was simple: