Open menu icon N-ARY CIRCLED PLUS OPERATOR
atoum

Features

atoum is a full-featured testing framework. Judge for yourself.

Flexible structure

Test suites, test cases, directory names… feel free to rename everything to fit your particular needs.

Execution engines

By default, atoum provides three execution engines:

  • Inline, one test case after another in the same process,
  • Isolate, one test case after another but each time in a new process,
  • Concurrent, “all” test cases at the same time in separated processes.

A specific engine can be defined per test case in addition to a default one with the @engine annotation.

Using the concurrent engine will provide a faster feedback, this will accelerate your development.

Vocabulary

Depending of the kind of tests we are making, there is several ways to write a test case. The “classic” (old) way is procedural:

<?php

$x      = 1;
$y      = 2;
$result = $x + $y;

$this->assertTrue($result === 3);

The “smarter” way by really using atoum’s asserters:

<?php

$x      = 1;
$y      = 2;
$result = $x + $y;

$this->integer($result)->isEqualTo(3);

The “academic” way:

<?php

$this
    ->given(
        $x = 1,
        $y = 2
    )
    ->when($result = $x + $y)
    ->then
        ->integer($result)
            ->isEqualTo(3);

In the later example, the given, when and then keywords are “empty asserters”. They execute nothing. They are used to provide a better test case design.

Meaningful asserters

atoum provides a full-featured set of natural and expressive assertions making test cases as much readable as possible. The following example asserts the integer 150 is greater than 100 and lower than or equal to 200:

<?php

$this
    ->integer(150)
        ->isGreaterThan(100)
        ->isLowerThanOrEqualTo(200);

The following example asserts that 1 - 0.97 is nearly equal to 0.03 (which is strictly false in Computer Science):

<?php

$this
    ->float(1 - 0.97)
        ->isNearlyEqualTo(0.03) // passes
        ->isEqualTo(0.03);      // fails

Arrays, strings, objects, exceptions… all of them have specific collections of asserters. In addition to provide a better readability, they provide a better feedback when a test fails because atoum knows what you meant to do.

A “diff” between the expected value and the computed value is also produced when a test fails.

Mocks

Mocks able to close dependencies of your system under test. Test cases will be faster to build and to execute. atoum provides mocking for:

  • Classes, by simply using the top-namespace mock (case insensitive); for instance, the following example will mock the Foo\Bar class and will provide a new implementation for the methodBaz method:
<?php

$mockedObject = new \Mock\Foo\Bar();

$this->calling($mockedObject)->methodBaz = function ($x) {
    return $x * 2;
};
  • Functions, by using the function “asserter”; the following example will mock the session_start PHP function and will provide a new implementation:
<?php

$this->function->session_start = function () {
    return false;
};
  • Constants, by using the constant “asserter”; the following example will mock the PHP_VERSION_ID constant and will provide a new value:
<?php

$this->constant->PHP_VERSION_ID = 606060; // troll spotted

Mocks are generated at runtime and they are just that easy to use.

Of course, you can mock class constructor, you can control the value to compute each time a method is called, you can assert that a method has been called at least once etc.

Virtual file system

When manipulating files or directories, having real files is not required. atoum provides a virtual file system allowing to fake real files and directories. Enter atoum://. The following example will create a virtual file and the resulting resource can be used like any other regular file resources:

<?php

$file = atoum\mock\streams\fs\file::get('fakeFile');
fwrite($file, 'foobar');
rewind($file);
// …
stream_get_contents($file); // string(6) "foobar"

As expected, you can control the permissions, the ownership, different times, content, parents etc.

Reports

Either test suites are run by one single user, or by a continous integration server. In both cases (but most importantly in the latter), having test reports is crucial to understand failures, regressions, performances etc. That’s why atoum is able to produce several reports like:

  • TAP, the Test Anything Protocol, a language agnostic format,
  • clover, a software and a format for test reports,
  • xUnit, a Jenkins plugin and a format for test reports,
  • Your own, yes, this is really easy to plug your own reporter.

Whatever you are using Jenkins, Travis or any other well-known softwares, they are likely to understand atoum.

Loop and autorun modes

In order to help you as much as possible, atoum provides the loop mode. Simply using the --loop option on the command-line tool will run all the tests and it will wait you to press Enter before restarting the run. If test cases were failling, atoum will only re-run these ones. You will save time and CPU. If no test cases were failling, atoum will re-run all your test suites.

$ bin/atoum … --loop
…
Press <Enter> to reexecute, press any other key and <Enter> to stop...

The autorun helps you to run any test cases in any file like a regular PHP file if the runner is included. It means you can avoid using the command-line tool. Thus, both following examples are equivalent (assuming the runner is included):

$ bin/atoum --files Test/Unit/Foo.php
$ # is equivalent to…
$ bin/atoum Test/Unit/Foo.php
$ # is equivalent to…
$ php Test/Unit/Foo.php

Configuration file in PHP

atoum’s configuration file is written in PHP. No YAML, no XML, no strange language. Only PHP for a maximum flexibility.

<?php

$script->addDefaultArguments(
    '--debug',
    '--use-tap-report',
    '--loop'
);
$runner->addTestsFromDirectory(__DIR__ . '/Test/Unit/');
// …

Note the global $script and $runner variables: reach any part of atoum to fit in your own workflow.

Third-party integration

atoum integrates well with those CI tools:

atoum has a great integration with those IDEs:

but atoum also plays well with:

You can also use atoum with your regular build tools and/or dependancy manager:

Fast

First, atoum comes with a concurrent engine, which makes it fast (and secure) by default. Second, atoum is lightweight. For instance, the following table shows the time and memory required to run atoum’s test suite and Hoa’s test suite, which are known to be important and intensive, both in terms of computation and memory:

This table illustrates how fast atoum is by showing numbers about big test suites.
atoum Hoa
Test suites 235 139
Test cases 1888 1304
Assertions 27,540 411,516
Time 61s 172s
Memory 464Mb 1328Mb

Extensions

atoum is extensible. The community writes extensions and the organization of atoum hosts and maintains some of them, like:

Most of the time, to install an extension you will just need to include it in your dependencies and add one line in your configuration file, like:

<?php

$extension = new mageekguy\atoum\ruler\extension()
$extension->addToRunner($runner);