9. Example
class Account
{
protected $balance;
public function __construct($initialAmount)
{
$this->balance = $initialAmount;
}
public function getBalance()
{
return $this->balance;
}
public function deposit($amount)
{
$this->balance += $amount;
}
}
10. Unit Test
class AccountTest extends PHpUnit_Framework_TestCase
{
public function testDepositIncreasesBalance()
{
$account = new Account(10);
$account->deposit(1);
$this->assertEquals(11, $account->getBalance());
}
}
11. Unit Test
PHPUnit 4.3.1 by Sebastian Bergmann.
Account
[x] Deposit increases balance
13. Give meaningful names to your
tests
public function testDeposit()
{
$account = new Account(10);
$account->deposit(1);
$this->assertEquals(
11,
$account->getBalance()
);
}
DON’T
14. Give meaningful names to your
tests
PHPUnit 4.3.1 by Sebastian Bergmann.
Account
[ ] Deposit
15. Give meaningful names to your
tests
public function testDepositIncreaseBalance()
{
$account = new Account(10);
$account->deposit(1);
$this->assertEquals(
11,
$account->getBalance()
);
}
16. Use the most specific
assertion available
public function testDepositIncreasesBalance()
{
$account = new Account(10);
$account->deposit(10);
$this->assertGreaterThan(
10,$account->getBalance()
);
}
DON’T
17. Use the most specific
assertion available
public function testDepositIncreasesBalance()
{
$account = new Account(10);
$account->deposit(10);
$this->assertEquals(20, $account->getBalance());
}
18. Use the most specific
assertion available
public function deposit($amount)
{
$this->balance += $amount;
if ($amount >= 10) {
$this->balance += 1;
}
return true;
}
19. Use the most specific
assertion available
There was 1 failure:
1) AccountTest::testDepositIncreasesBalance
Failed asserting that 21 matches expected 20.
AccountTest.php:14
20. Don’t forget about protected
methods
class Account
{
public function deposit($amount)
{
if ($this->validateAmount($amount)) {
$this->balance += $amount;
} else {
throw new Exception('Invalid amount');
}
}
}
21. Don't forget about
your protected methods
protected function validateAmount($amount)
{
if ($amount < 0) {
return false;
} else {
return true;
}
}
22. Don't forget about
your protected methods
public function testValidateAmountWithNegativeIsFalse()
{
$account = new Account(10);
$this->assertFalse($account->validateAmount(-1));
}
Fatal error: Call to protected method Account::validateAmount()
23. Don't forget about
your protected methods
public function testValidateAmountWithNegativeIsFalse()
{
$account = new Account(10);
$reflection = new ReflectionObject($account);
$method = $reflection->getMethod('validateAmount');
$method->setAccessible(true);
$this->assertFalse(
$method->invokeArgs($account, array(-1))
);
}
24. Don't forget about
your protected methods
PHPUnit 4.3.1 by Sebastian Bergmann.
Account
[x] Deposit increases balance
[x] Validate amount with negative is false
25. Test just one thing at a time
public function deposit($amount)
{
if ($amount == 0) {
return false;
}
$this->balance += $amount;
return true;
}
26. Test just one thing at a time
public function testDepositIncreasesBalance()
{
$account = new Account(10);
$this->assertTrue($account->deposit(1));
$this->assertEquals(11, $account->getBalance());
$this->assertFalse($account->deposit(0));
}
27. Test just one thing at a time
PHPUnit 4.3.1 by Sebastian Bergmann.
.
Time: 35 ms, Memory: 3.00Mb
OK (1 test, 3 assertions)
28. Test just one thing at a time
public function deposit($amount)
{
if ($amount < 0) {
NEW CRITERIA
return false;
}
$this->balance += $amount;
return true;
}
29. Test just one thing at a time
PHPUnit 4.3.1 by Sebastian Bergmann.
There was 1 failure:
1) AccountTest::testDepositIncreasesBalance
Failed asserting that true is false.
AccountTest.php:15
FAILURES!
Tests: 1, Assertions: 3, Failures: 1.
30. Test just one thing at a time
public function testDepositIncreasesBalance()
{
$account = new Account(10);
$this->assertTrue($account->deposit(1));
$this->assertEquals(11, $account->getBalance());
}
public function
testDepositWithNegativeShouldReturnFalse()
{
$account = new Account(10);
$this->assertFalse($account->deposit(-1));
}
31. Test just one thing at a time
PHPUnit 4.3.1 by Sebastian Bergmann.
..
Time: 49 ms, Memory: 3.00Mb
OK (2 tests, 3 assertions)
32. Use Data Providers for
repetitive tests
class Score
{
protected $score;
public function update($balance, $numberCc,
$amountInLoans)
{
// do something ...
return $newScore;
}
}
33. Use Data Providers for
repetitive tests
class ScoreTest extends PHpUnit_Framework_TestCase
{
public function testScoreSomething1()
{
$score = new Score(10);
$this->assertEquals(300, $score->update(100, 0, 1));
}
public function testScoreSomething2()
{
$score = new Score(10);
$this->assertEquals(99, $score->update(100, 1, 2));
}
}
34. Use Data Providers for
repetitive tests
/**
* @dataProvider scoreProvider
*/
public function testScore($balance, $numberCc,
$amountInLoans, $expectedScore)
{
$score = new Score(10);
$this->assertEquals(
$expectedScore,
$score->update($balance, $numberCc, $amountInLoans)
);
}
35. Use Data Providers for
repetitive tests
public function scoreProvider()
{
return array(
array(100, 0, 1, 300),
array(100, 1, 2, 99),
);
}
36. Use Data Providers for
repetitive tests
PHPUnit 4.3.1 by Sebastian Bergmann.
..
Time: 25 ms, Memory: 3.00Mb
OK (2 tests, 2 assertions)
37. Isolate your test
public function wire($amount, SwiftInterface $targetBank)
{
if ($targetBank->transfer($amount)) {
$this->balance -= $amount;
return true;
} else {
return false;
}
}
38. Isolate your test
class Hsbc implements SwiftInterface {
public function transfer($amount)
{
// slow method
}
}
39. Isolate your test
public function
testWireTransferShouldReturnTrueIfSuccessful()
{
$account = new Account(10);
$bank = new Hsbc();
$this->assertTrue($account->wire(5, $bank));
}
40. Isolate your test
public function
testWireTransferShouldReturnFalseIfFailed()
{
// how to fail?
$account = new Account(10);
$bank = new Hsbc();
$this->assertFalse($account->wire(5, $bank));
}
41. Isolate your test
public function
testWireTransferShouldReturnTrueIfSuccessful()
{
$account = new Account(10);
$bank = $this->getMock(‘Hsbc');
$bank->expects($this->any())
->method('transfer')
->will($this->returnValue(true));
$this->assertTrue($account->wire(5, $bank));
}
42. Isolate your test
public function
testWireTransferShouldReturnFalseIfFailed()
{
$account = new Account(10);
$bank = $this->getMock('Hsbc');
$bank->expects($this->any())
->method('transfer')
->will($this->returnValue(false));
$this->assertFalse($account->wire(5, $bank));
}
43. Specify what you are testing
with @covers
Use --coverage-html to generate the code
coverage report of your code
45. Specify what you are testing
with @covers
class Exchange {
public function convert($amountUsd, $targetCurrency)
{
// Do some conversion
}
}
46. Specify what you are testing
with @covers
public function convertBalance($targetCurrency)
{
$exchange = new Exchange();
return $exchange->convert($this->balance, $targetCurrency);
}
47. Specify what you are testing
with @covers
public function testConvertBalance()
{
$account = new Account(10);
$this->assertLessThan(
10, $account->convertBalance('GBP')
);
}