atoum/bdd-extension
This extensions helps you to write your tests (specs) in a Behavior Driven development fashion., (*1)
Example
public function should_format_underscore_separated_method_name()
{
$this
->given($formatter = new testedClass())
->then
->invoking->format(__FUNCTION__)->on($formatter)
->shouldReturn('should format underscore separated method name')
;
}
and the output will look like this :, (*2)
, (*3)
Install it
Install extension using composer:, (*4)
composer require --dev atoum/bdd-extension
Enable the extension using atoum configuration file:, (*5)
<?php
// .atoum.php
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
use atoum\atoum\bdd;
$extension = new bdd\extension($script);
$runner->addExtension($extension);
Use it
Your first spec
The extension requires you to place your specs in a specs
namespace and make them extend atoum\spec
. Let's write a
spec for the jubianchi\example\formatter
class:, (*6)
<?php
namespace jubianchi\example\specs;
use atoum;
use jubianchi\example\formatter as testedClass;
class formatter extends atoum\spec
{
public function should_format_underscore_separated_method_name()
{
$this
->given($formatter = new testedClass())
->then
->invoking->format(__FUNCTION__)->on($formatter)
->shouldReturn('should format underscore separated method name')
;
}
public function shouldFormatCamelCaseMethodName()
{
$this
->given($formatter = new testedClass())
->then
->invoking->format(__FUNCTION__)->on($formatter)
->shouldReturn('should format camel case method name')
;
}
public function should_formatMixed__MethodName()
{
$this
->given($formatter = new testedClass())
->then
->invoking->format(__FUNCTION__)->on($formatter)
->shouldReturn('should format mixed method name')
;
}
}
Running your first spec
$ vendor/bin/atoum -d specs
> jubianchi\example\formatter...
✘ should format camel case method name
256: Tested class 'jubianchi\example\formatter' does not exist for test class 'jubianchi\example\specs\formatter'
File: /atoum-bdd-extension/formatter.php
✘ should format underscore separated method name
256: Tested class 'jubianchi\example\formatter' does not exist for test class 'jubianchi\example\specs\formatter'
File: /atoum-bdd-extension/formatter.php
✘ should format mixed method name
256: Tested class 'jubianchi\example\formatter' does not exist for test class 'jubianchi\example\specs\formatter'
File: /atoum-bdd-extension/formatter.php
Failure (1 spec, 3/3 examples, 0 void example, 0 skipped example, 0 uncompleted example, 0 failure, 3 errors, 0 exception)!
And run it again until you get green:, (*7)
$ vendor/bin/atoum -d specs
> jubianchi\example\formatter...
✔ should format underscore separated method name
✔ should format camel case method name
✔ should format mixed method name
Success (1 spec, 3/3 examples, 0 void example, 0 skipped example, 6 assertions)!
You can use the --loop
flag to work incrementally: vendor/bin/atoum -d specs --loop
, (*8)
Reading the report
The spec report uses a set of icon to identify examples' statuses:, (*9)
-
✘
to mark failed examples (error, exception or assertion failure)
-
✔
to mark passed examples
-
↣
to mark skipped examples
-
∅
to mark void examples (not implemented specs)
Spec syntax
Invoking methods
Invoking a method is the process of calling a method on a tested object in a way that will allow the tester to assert
on method behavior:, (*10)
<?php
namespace jubianchi\example\specs;
use atoum;
use jubianchi\example\formatter as testedClass;
class formatter extends atoum\spec
{
public function should_invoke_method()
{
$this
->given($formatter = new testedClass())
->then
->invoking->format(__FUNCTION__)->on($formatter)
// ...
;
}
}
This example will invoke the format
method of the $formatter
object with one argument, __FUNCTION__
., (*11)
There are several way of invoking method, depending on which syntax you prefer:, (*12)
$this->invoking->format(__FUNCTION__)->on($formatter);
$this->invoking('format', __FUNCTION__)->on($formatter);
$this->invokingFormat(__FUNCTION__)->on($formatter);
Asserting on returned values
The spec extension provides some shortcut to assert on method return value., (*13)
<?php
namespace jubianchi\example\specs;
use atoum;
use jubianchi\example\formatter as testedClass;
class formatter extends atoum\spec
{
public function should_format_underscore_separated_method_name()
{
$this
->given($formatter = new testedClass())
->then
->invoking->format(__FUNCTION__)->on($formatter)
->shouldReturn('should format underscore separated method name')
;
}
}
As you can see, shouldReturn
lets you assert on invoked method return value. Again, there are several way of doing the
same:, (*14)
$this->invoking->format(__FUNCTION__)->on($formatter)->shouldReturn('...');
$this->invoking->format(__FUNCTION__)->on($formatter)->returns('...');
$this->invoking->format(__FUNCTION__)->on($formatter)->should->return('...');
Calling shouldReturn
with a parameter will fallback on the atoum\asserters\variable::isEqual
assertion which is the
less strict one in atoum. You can of course use strict assertions to do some type checking:, (*15)
$this->invoking->format(__FUNCTION__)->on($formatter)->shouldReturn->string->isEuqlaTo('...')
Asserting on thrown exceptions
Asserting on exception is quite simple and similar to asserting on returned values:, (*16)
<?php
namespace jubianchi\example\specs;
use atoum;
use jubianchi\example\formatter as testedClass;
class formatter extends atoum\spec
{
public function should_format_underscore_separated_method_name()
{
$this
->given($formatter = new testedClass())
->then
->invoking->format(uniqid())->on($formatter)
->shouldThrow('invalidArgumentException')
;
}
}
As for shouldReturn
, shouldThrow
provides some alternative synatxes:, (*17)
$this->invoking->format(__FUNCTION__)->on($formatter)->shouldThrow('exception');
$this->invoking->format(__FUNCTION__)->on($formatter)->throws('exception');
$this->invoking->format(__FUNCTION__)->on($formatter)->should->throw('exception');
Calling shouldThrow
this way will fallback on atoum\asserters\exception::isInstanceOf
, if you don't want to check
the exception type, you can simple omit the argument:, (*18)
$this->invoking->format(__FUNCTION__)->on($formatter)->shouldThrow;
$this->invoking->format(__FUNCTION__)->on($formatter)->throws;
$this->invoking->format(__FUNCTION__)->on($formatter)->should->throw;
Of course, you can also check the exception message using regular assertions:, (*19)
$this->invoking->format(__FUNCTION__)->on($formatter)->shouldThrow->hasMessage('...');
$this->invoking->format(__FUNCTION__)->on($formatter)->throws('invalidArgumentException')->hasMessage('...');
Links
Licence
bdd-extension is released under the BSD-3-Clause. See the bundled LICENSE file for detail., (*20)
, (*21)