Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Unit testing with PHPUnit

Unit testing with PHPUnit

Adam

May 28, 2015
Tweet

More Decks by Adam

Other Decks in Programming

Transcript

  1. XUnit / Test execution setUp(); tearDown(); Create our isolated “world”

    for the current test Body of the test - all the tests run here Clean up our “world”
  2. Example <?php class PlayerTest extends PHPUnit_Framework_TestCase { public function testTakesDamage()

    { $player = new Player([‘health’ => 100]); $player->takesDamage(17); $this->assertEquals(83, $player->health()); } }
  3. Fixtures class PlayerTest extends PHPUnit_Framework_TestCase { protected $player; protected function

    setUp() { $this->player = new Player([‘health’ => 100]); } public function testTakesTinyDamage() { $player->takesDamage(5); $this->assertEquals(95, $player->health()); } public function testTakesHugeDamage() { $player->takesDamage(60); $this->assertEquals(40, $player->health()); } }
  4. There are tons! Assertions https://phpunit.de/manual/current/en/appendixes.assertions.html assertEquals assertContains assertInstanceOf assertTrue assertFalse

    assertNull assertLessThan assertXmlFileEqualsXmlFile assertFileExist assertCount assertEmpty assertRegExp assert*
  5. Feed test methods with various data Good for validation Must

    be public Either returns with an array of arrays or returns with an iterable object Data Providers
  6. Data Providers class PlayerTest extends PHPUnit_Framework_TestCase { /** * @dataProvider

    damageProvider */ public function testTakesDamage($damage) { $player->takesDamage($damage); $this->assertEquals(100 - $damage, $player->health()); } public function damageProvider() { return [ [44], [23], [76] ]; } }
  7. If a method generates output For example with print or

    echo PHPUnit uses Output Buffering Testing output
  8. Testing output class PlayerTest extends PHPUnit_Framework_TestCase { public function testPrintName()

    { $this->expectOutputString(‘Crash’); $player->printName(); } }
  9. Testing exceptions class PlayerTest extends PHPUnit_Framework_TestCase { /** * @expectedException

    InvalidDamageException */ public function testTakesDamage() { $player->takesDamage(-5); } }
  10. A test method depends on other(s) Producer which serves return

    data Consumer which depends on
 one or more producers Test dependencies
  11. Test dependencies class PlayerTest extends PHPUnit_Framework_TestCase { public function testIsPlayerDead()

    { $player = new Player([‘health’ => 0]); $this->assertTrue($player->isDead()); return $player; } /** * @depends testIsPlayerDead * @expectedException DeadPlayerException */ public function testTakesDamageOnDeadPlayer($deadPlayer) { $deadPlayer->takesDamage(10); } }
  12. We have to write some tests No time So, create

    test list
 Incomplete tests
  13. class PlayerTest extends PHPUnit_Framework_TestCase { public function testPlayerCreation() { }

    public function testPlayerIsDead() { } public function testPlayerTakesDamage() { } } Incomplete tests C orrect?
  14. class DatabaseTest extends PHPUnit_Framework_TestCase { protected function setUp() { if

    (!extension_loaded(‘mysqli’)) { $this->markTestSkipped(‘Whops MySQLi extension!’); } } } Skipped tests E nvironm ent dependent
  15. Use specific assertion Name your tests after their intention Keep

    tests small Keep tests fast Test behavior (not methods) Best practices
  16. class DirTest extends PHPUnit_Extensions_Database_TestCase { /** * @var vfsStreamDirectory */

    protected $vfsRootDir; protected function setUp() { $this->vfsRootDir = vfsStream::setup(‘root_dir_name’); } public function testDir() { # $this->vfsRootDir->url(); # vfsStream::newDirectory(‘dir_name’, 0444)->at($this->vfsRootDir); } } Filesystem test
  17. class PlayerTest extends PHPUnit_Extensions_Database_TestCase { public function getConnection() { $pdo

    = new PDO( $GLOBALS[‘DB_DSN'], $GLOBALS[‘DB_USER'], $GLOBALS[‘DB_PASSWD'] ); return $this->createDefaultDBConnection($pdo, $GLOBALS['DB_DBNAME']); } public function getDataSet() { return $this->createFlatXMLDataSet('player-seed.xml'); } } DB test S chem a? extract to abstract
  18. <?xml version="1.0" encoding="UTF-8" ?> <phpunit> <php> <var name="DB_DSN" value="mysql:dbname=players;host=localhost" />

    <var name="DB_USER" value="user" /> <var name="DB_PASSWD" value="password" /> <var name="DB_DBNAME" value="players" /> </php> </phpunit> DB test / Config phpunit --configuration dev-adam.xml
  19. File-based DataSet XML (FLAT-XML, XML, MYSQL-XML) YAML CSV PHP array

    Query-based DataSet Composite DataSet DataSet Filter DB tests / Expectations
  20. <?xml version="1.0" ?> <dataset> <players id="1" name="Crash" health="100" /> <players

    id="2" name="Hunter" health="100" /> </dataset> Flat XML DataSet N U L L ?
  21. class PlayerTest extends PHPUnit_Extensions_Database_TestCase { public function getDataSet() { return

    $this->createFlatXMLDataSet('players-seed.xml'); } } Flat XML DataSet
  22. <?xml version="1.0" ?> <dataset> <table name="players"> <column>id</column> <column>name</column> <column>health</column> <row>

    <value>1</value> <value>Crash</value> <value>100</value> </row> <row> <value>2</value> <value>Hunter</value> <null /> </row> </table> </dataset> XML DataSet
  23. class PlayerTest extends PHPUnit_Extensions_Database_TestCase { public function testAddPlayer() { $this->assertEquals(

    1, $this->getConnection()->getRowCount('players') ); # add Player to the players db table $this->assertEquals( 2, $this->getConnection()->getRowCount('players') ); } } DB Assertions / RowCount
  24. class PlayerTest extends PHPUnit_Extensions_Database_TestCase { public function testAddPlayer() { #

    add Player to the players db table $queryTable = $this->getConnection()->createQueryTable( 'players', 'SELECT * FROM players' ); $expectedTable = $this ->createFlatXmlDataSet('expectedPlayer.xml') ->getTable('players'); $this->assertTablesEqual($expectedTable, $queryTable); } } DB Assertions / Table State
  25. $plugin = new Guzzle\Plugin\Mock\MockPlugin(); $plugin->addResponse(new Guzzle\Http\Message\Response(200)); $client = new Guzzle\Http\Client();

    $client->addSubscriber($plugin); $request = $client->get('http://www.test.com/'); $request->send(); Mocking API call
  26. class PlayerTest extends PHPUnit_Framework_TestCase { public function testHealth() { $stub

    = $this ->getMockBuilder('Player') ->getMock(); $stub ->method('health') ->willReturn(15); # $stub->health() ~= $player->health() } } Test Doubles / Stub
  27. class Subject { public function doSomething(Observer $observer) { $observer->update(‘something’) }

    } Test Doubles / Mock class Observer { public function update($argument) { # … } }
  28. class SubjectTest extends PHPUnit_Framework_TestCase { public function testObserversAreUpdated() { $observer

    = $this ->getMockBuilder('Observer') ->setMethods(array('update')) ->getMock(); $observer ->expects($this->once()) ->method('update') ->with($this->equalTo(‘something')); $subject = new Subject(); $subject->doSomething($observer); } } Test Doubles / Mock
  29. . |— src | `— foo | `— bar |

    `— Baz.php `— tests | — api `— unit `— foo `— bar `— BazTest.php Organazing Tests