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.
Installation and Requirements
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):
Writing the Tests
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
<?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.
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.
The Nette Tester runner searches the specified directory and all subdirectories and searches for tests, which are files
*Test.php. It will also find our test
ArrayTest.php, as it matches
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.3.3 Note: No php.ini is used. PHP 7.4.8 (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.
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.
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.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: