- You want to reduce your messy "setUp" methods that init objects for ALL tests. But most of the time, they are not required all together.
- You want to have explicit setup/arrange for each tests... Or reuse them!
- You want to have tests easy to read
- You want to put forward real important setup/expectations/fixtures and put the rest as annotations
It's time to refactor your ugly "setUp"!
- PHP: Compatible with PHP 5.3 to the last version (7.1) and HHVM
- PHPUnit: Compatible with version 3., 4., 5.*
See build here. Some builds fail because some version of PHPUnit are not compatible with some PHP versions.
Simply add this to your composer.json
file:
"require": {
"nikoms/phpunit-arrange": "dev-master"
}
Then run php composer.phar install
To activate the plugin. Add the listener to your phpunit.xml(.dist) file:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
...
<listeners>
<listener class="Nikoms\PhpUnit\Listener\ArrangeListener" file="vendor/nikoms/phpunit-arrange/src/ArrangeListener.php" />
</listeners>
</phpunit>
"Use" the plugin on the top of your test:
use Nikoms\PhpUnit\Annotation\Arrange;
And then, let the magic begin...
It's possible to easily call a custom "setUp" method before the test.
use Nikoms\PhpUnit\Annotation\Arrange;
class ExampleTest extends \PHPUnit_Framework_TestCase
{
public function initConnectedUser()
{
$this->user = new User();
$this->user->isConnected = true;
}
/**
* @Arrange("initConnectedUser")
*/
public function testSomething()
{
$this->assertSame('Nicolas', $this->user->name);
// Do something with your $this->user..
}
}
It's possible to give an argument to the arrange method. It works with a string, an array, a constant, etc...
use Nikoms\PhpUnit\Annotation\Arrange;
class ExampleTest extends \PHPUnit_Framework_TestCase
{
/**
* @param string $name
* @return User
*/
public function iAmConnectedWithTheName($name)
{
$this->user = new User();
$this->user->isConnected = true;
$this->user->name = $name;
}
/**
* @Arrange(iAmConnectedWithTheName="Nicolas")
*/
public function testSomething()
{
$this->assertSame('Nicolas', $this->user->name);
// Do something with your $this->user..
}
}
If the arrange method returns something, then it is put as argument in the test method
use Nikoms\PhpUnit\Annotation\Arrange;
class ExampleTest extends \PHPUnit_Framework_TestCase
{
/**
* @param string $name
* @return User
*/
public function iAmConnectedWithTheName($name)
{
$user = new User();
$user->isConnected = true;
$user->name = $name;
return $user;
}
/**
* @Arrange(iAmConnectedWithTheName="Nicolas")
*/
public function testSomething(User $user)
{
$this->assertSame('Nicolas', $user->name);
// Do something with your user..
}
}
If the arrange method returns something, then it is put as argument in the test method
use Nikoms\PhpUnit\Annotation\Arrange;
class ExampleTest extends \PHPUnit_Framework_TestCase
{
/**
* @param string $name
* @return User
*/
public function iAmConnectedWithTheName($name)
{
$user = new User();
$user->isConnected = true;
$user->name = $name;
return $user;
}
/**
* @param User $user
* @param string $group
* @return User
*/
public function memberOfGroup($user, $group)
{
$user->group = $group;
return $user;
}
/**
* @Arrange(iAmConnectedWithTheName="Nicolas", memberOfGroup=User::GROUP_ADMIN)
* @param User $user
*/
public function testSomething(User $user)
{
$this->assertSame(User::GROUP_ADMIN, $user->group);
$this->assertSame('Nicolas', $user->name);
// Do something with your user..
}
}
Of course, it's possible to have multiple arrange for the same test method
use Nikoms\PhpUnit\Annotation\Arrange;
class ExampleTest extends \PHPUnit_Framework_TestCase
{
/**
* @param string $name
* @return User
*/
public function iAmConnectedWithTheName($name)
{
$user = new User();
$user->isConnected = true;
$user->name = $name;
return $user;
}
/**
* @Arrange(iAmConnectedWithTheName="Nicolas")
* @Arrange(iAmConnectedWithTheName="Laura")
* @param User $user
*/
public function testSomething(User $nicolas, User $laura)
{
$this->assertSame('Nicolas', $nicolas->name);
$this->assertSame('Laura', $laura->name);
// Do something with your user..
}
}
@dataProvider can be used to fill arrange methods.
use Nikoms\PhpUnit\Annotation\Arrange;
class ExampleTest extends \PHPUnit_Framework_TestCase
{
/**
* @return array
*/
public function provideNames()
{
return array(
array('Nicolas'),
array('Laura'),
);
}
/**
* @param string $name
* @return User
*/
public function iAmConnectedWithTheName($name)
{
$user = new User();
$user->isConnected = true;
$user->name = $name;
return $user;
}
/**
* @dataProvider provideNames
* @Arrange("iAmConnectedWithTheName")
*
* @param string $dataProviderValue
* @param User $user
*/
public function testSomething($dataProviderValue, User $user)
{
// The user has the name given by the "@dataProvider":
// First "Nicolas", then "Laura".
$this->assertSame($dataProviderValue, $user->name);
// Do something with your user..
}
}
Because it's the name of a step in tests as explained here.
Follow the "3-As" pattern for test methods: Arrange, Act, Assert. Specifically, use separate code paragraphs (groups of lines of code separated by a blank line) for each of the As.
- Arrange is variable declaration and initialization.
- Act is invoking the code under test.
- Assert is using the Assert.* methods to verify that expectations were met. Following this pattern consistently makes it easy to revisit test code.
- Refac a little
- Make an HTML testdox to have a nice BDD style output
- Unit test Listener & printer... Even if it's already tested with the tests/ExampleTest.php
- Add the possibility to add "ignoredAnnotationNames" in annotationReaderFactory