SlideShare a Scribd company logo
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
watch -n 15 -d 
   find tests/ -mmin -1 -iname '"*.php"' -exec 
   'phpunit -c tests/phpunit.xml {} ;'
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
➡
➡
➡
➡
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
library
!"" Controller.php
!"" Response.php
!"" Request.php
!"" View.php
#
!"" Request
#   $"" Http.php
!"" Response
#   $"" Http.php
!"" Test
#   $"" ControllerTestCase.php
$"" View
     $"" Html.php
Advanced php testing in action
Advanced php testing in action
project
!"" application
#   !"" controllers
#   #   $"" IndexController.php
#   !"" models
#   #   $"" Todo.php
#   $"" views
#       $"" index.phtml
$"" tests
    !"" application
    #   !"" controllers
    #   #   $"" IndexControllerTest.php
    #   !"" models
    #   #   $"" TodoTest.php
    #   $"" views
    #       $"" InterfaceTest.php
    !"" bootstrap.php
    $"" phpunit.xml
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
CREATE DATABASE `testing` CHARSET=utf8;
USE `testing`;

CREATE TABLE `todo` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '        ',
  `task` varchar(100) NOT NULL COMMENT '   ',
  `done` enum('y','n') NOT NULL DEFAULT 'n' COMMENT '       ',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Todo';
Advanced php testing in action
<phpunit colors="true" bootstrap="./bootstrap.php">
  <testsuite name="Application Test Suite">
    <directory>./application</directory>
  </testsuite>
  <testsuite name="Library Test Suite">
    <directory>./library</directory>
  </testsuite>
  <php>
    <var name="DB_DSN" value="mysql:dbname=testing;host=127.0.0.1" />
    <var name="DB_USER" value="username" />
    <var name="DB_PASSWD" value="password" />
  </php>
</phpunit>
➡ fetchAll()
➡ add($task)
➡ done($id)
Advanced php testing in action
<?php                                         <?php

class TodoTest extends                        class Todo
    PHPUnit_Framework_TestCase                {
{                                                 protected static $_pdo = null;
    private $_pdo = null;                         
                                                  public static function setDb(PDO $pdo)
    private $_todo = null;                        {
                                                      self::$_pdo = $pdo;
    public function setUp()                       }
    {
        $this->_pdo = new PDO(
                $GLOBALS['DB_DSN'],
                $GLOBALS['DB_USER'],
                $GLOBALS['DB_PASSWD']);
        $this->_pdo
            ->query('TRUNCATE TABLE todo');

        Todo::setDb($this->_pdo);
        $this->_todo = new Todo();
    }

    public function tearDown()
    {
        $this->_pdo
            ->query('TRUNCATE TABLE todo');
    }
public function testAdd()                 public function add($task)
{                                         {
    $this->assertEquals(                      $query = 'INSERT INTO todo (task) '
        1,                                           . 'VALUES (?)';
        $this->_todo->add('Task 1')
    );                                        self::$_pdo->prepare($query)
                                                  ->execute(array($task));
    $this->assertEquals(
        2,                                    return self::$_pdo->lastInsertId();
        $this->_todo->add('Task 2')       }
    );                                    
}
public function testFetchAll()                  public function fetchAll()
{                                               {
    $this->_todo->add('Task 1', 'm');               $query = 'SELECT * FROM todo';
    $this->_todo->add('Task 2', 'f');               $stmt  = self::$_pdo
                                                        ->query($query);
    $result = $this->_todo->fetchAll();
                                                  return $stmt
    $this->assertEquals(                              ->fetchAll(PDO::FETCH_ASSOC);
        2,                                    }
        count($result)
    );

    $this->assertContains(
       'Task 1',
        $result[0]
    );

    $this->assertContains(
       'Task 2',
        $result[1]
    );
}
public function testDone()             public function done($id)
    {                                      {
        $this->_todo->add('Task 1');           $query = 'UPDATE todo '
        $this->_todo->add('Task 2');                  . 'SET done = 'y''
                                                      . 'WHERE id = ?';
        $this->assertEquals(                   $stmt  = self::$_pdo->prepare($query);
            1,
            $this->_todo->done(1)              $stmt->execute(array($id));
        );
                                               return $stmt->rowCount();
        $this->assertEquals(               }
            1,                         }
            $this->_todo->done(2)
        );

        $this->assertEquals(
            0,
            $this->_todo->done(3)
        );
    }
}
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
➡	 
➡
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
➡
➡
➡
➡
Advanced php testing in action
<?php

class InterfaceTest extends PHPUnit_Extensions_SeleniumTestCase
{

    protected function setUp()
    {
        $this->setBrowser("*chrome");
        $this->setBrowserUrl("http://test.dev/");
    }

    public function testMyTestCase()
    {
        $this->open("/advanced_php_testing/mvc/");
        $this->type("id=new-todo", "Task 1");
        $this->keyPress("id=new-todo", "13");
        $this->waitForPageToLoad("30000");
        $this->assertEquals("Task 1",
            $this->getText("//ul[@id='todo-list']/div[1]/div/div"));
        $this->type("id=new-todo", "Task 2");
        $this->keyPress("id=new-todo", "13");
        $this->waitForPageToLoad("30000");
        $this->assertEquals("Task 2",
            $this->getText("//ul[@id='todo-list']/div[2]/div/div"));
    }
}
Advanced php testing in action
<?php

class InterfaceTest extends PHPUnit_Extensions_SeleniumTestCase
{

    protected function setUp()
    {
        $this->_pdo = new PDO(
                        $GLOBALS['DB_DSN'],
                        $GLOBALS['DB_USER'],
                        $GLOBALS['DB_PASSWD']);
        $this->_pdo->query('TRUNCATE TABLE todo');

        Todo::setDb($this->_pdo);
        $this->_todo = new Todo();

        $this->setBrowser("*chrome");
        $this->setBrowserUrl("http://test.dev/");
    }
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
<?php

class Request
{
    protected $_headers = array(
        'REQUEST_METHOD' => 'GET',
    );

    public function setHeader($name, $value)
    {
        $this->_headers[$name] = $value;
    }

    public function isPost()
    {
        return ('POST' === $this->_headers['REQUEST_METHOD']);
    }

    public function isAjax()
    {
        return ('XMLHttpRequest' === $this->_headers['X_REQUESTED_WITH']);
    }
<?php

class Request_Http extends Request
{
    public function isPost()
    {
        return ('POST' === $_SERVER['REQUEST_METHOD']);
    }

    public function isAjax()
    {
        return ('XMLHttpRequest' === $_SERVER['X_REQUESTED_WITH']);
    }
}
Advanced php testing in action
<?php

class Response
{
    protected $_headers = array(
        'Content-Type' => 'text/html; charset=utf-8',
    );

    public function setHeader($name, $content)
    {
        $this->_headers[$name] = $content;
    }

    public function getHeader($name)
    {
        return isset($this->_headers[$name])
             ? $this->_headers[$name]
             : null;
    }

    protected function sendHeaders()
    {
        // do nothing
    }
Advanced php testing in action
$controller = new IndexController(new Todo());
$controller->setRequest(new Request_Http())
        ->setResponse(new Response_Http())
        ->sendResponse(true)
        ->dispatch();




$controller = new IndexController(new Todo());
$controller->setRequest(new Request())
        ->setResponse(new Response())
        ->dispatch();
Advanced php testing in action
<?php

class Test_ControllerTestCase extends PHPUnit_Framework_TestCase
{
    protected $_controller = null;

    protected $_request = null;

    protected $_response = null;

    public function setUp()
    {
        $this->_controller->setRequest($this->_request)
                            ->setResponse($this->_response);
    }

    public function dispatch($url)
    {
        $this->_parseUrl($url);
        $this->_controller->dispatch();
        return $this;
    }

    protected function _parseUrl($url)
    {
        $urlInfo = parse_url($url);
        if (isset($urlInfo['query'])) {
            parse_str($urlInfo['query'], $_GET);
        }
    }
➡ assertAction($action)
➡ assertResponseCode($code)
➡ assertRedirectTo($url)
<?php

class IndexControllerTest extends Test_ControllerTestCase
{
    public function setUp()
    {
        $todo = new Todo();
        $this->_request = new Request();
        $this->_response = new Response();
        $this->_controller = new IndexController($todo);
        parent::setUp();
    }

    public function tearDown()
    {
        $this->_request->reset();
        $this->_response->reset();
    }

    public function testHome()
    {
        $this->dispatch('/');
        $this->assertAction('index')
                ->assertResponseCode(200);
    }
Advanced php testing in action
Advanced php testing in action
Advanced php testing in action
<?php

class IndexControllerTest extends Test_ControllerTestCase
{
    public function setUp()
    {
        $todo = $this->_setUpTodo();
        $this->_controller = new IndexController($todo);
        // ...
    }

    protected function _setUpTodo()
    {
        $todo = Phake::mock('Todo');
        Phake::when($todo)->fetchAll()->thenReturn(array(
            array(
                'id' => 1,
                'task' => 'Task 1',
                'done' => 'n',
            ),
        ));
        return $todo;
    }
Advanced php testing in action
➡ assertQuery($selector)
➡ assertQueryContain($selector, $text)
Advanced php testing in action
<?php

class IndexControllerTest extends Test_ControllerTestCase
{
    // ...

    public function testHome()
    {
        $this->dispatch('/');
        $this->assertAction('index')
                ->assertResponseCode(200)
                ->assertQuery('#todo-list');
    }

    public function testAdd()
    {
        $this->_request->setMethod('POST');
        $_POST['task'] = 'Task 1';
        $this->dispatch('/?act=add')
                ->assertAction('add')
                ->assertRedirectTo('./')
                ->assertResponseCode(200)
                ->assertQueryContain(
                    '#todo-list>.todo>.display>.todo-text',
                    'Task 1'
                );
    }
Advanced php testing in action
➡

➡

➡
Advanced php testing in action
➡	               	 


➡	              	 


➡	    	               	 
                           	 
➡
Advanced php testing in action
Advanced php testing in action

More Related Content

Advanced php testing in action

  • 6. watch -n 15 -d find tests/ -mmin -1 -iname '"*.php"' -exec 'phpunit -c tests/phpunit.xml {} ;'
  • 23. library !"" Controller.php !"" Response.php !"" Request.php !"" View.php # !"" Request #   $"" Http.php !"" Response #   $"" Http.php !"" Test #   $"" ControllerTestCase.php $"" View    $"" Html.php
  • 26. project !"" application #   !"" controllers #   #   $"" IndexController.php #   !"" models #   #   $"" Todo.php #   $"" views #   $"" index.phtml $"" tests !"" application #   !"" controllers #   #   $"" IndexControllerTest.php #   !"" models #   #   $"" TodoTest.php #   $"" views #   $"" InterfaceTest.php !"" bootstrap.php $"" phpunit.xml
  • 31. CREATE DATABASE `testing` CHARSET=utf8; USE `testing`; CREATE TABLE `todo` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT ' ', `task` varchar(100) NOT NULL COMMENT ' ', `done` enum('y','n') NOT NULL DEFAULT 'n' COMMENT ' ', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Todo';
  • 33. <phpunit colors="true" bootstrap="./bootstrap.php"> <testsuite name="Application Test Suite"> <directory>./application</directory> </testsuite> <testsuite name="Library Test Suite"> <directory>./library</directory> </testsuite> <php> <var name="DB_DSN" value="mysql:dbname=testing;host=127.0.0.1" /> <var name="DB_USER" value="username" /> <var name="DB_PASSWD" value="password" /> </php> </phpunit>
  • 36. <?php <?php class TodoTest extends class Todo PHPUnit_Framework_TestCase { {     protected static $_pdo = null; private $_pdo = null;          public static function setDb(PDO $pdo) private $_todo = null;     {         self::$_pdo = $pdo; public function setUp()     } { $this->_pdo = new PDO( $GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD']); $this->_pdo ->query('TRUNCATE TABLE todo'); Todo::setDb($this->_pdo); $this->_todo = new Todo(); } public function tearDown() { $this->_pdo ->query('TRUNCATE TABLE todo'); }
  • 37. public function testAdd()     public function add($task) {     { $this->assertEquals(         $query = 'INSERT INTO todo (task) ' 1,  . 'VALUES (?)'; $this->_todo->add('Task 1') );         self::$_pdo->prepare($query) ->execute(array($task)); $this->assertEquals( 2,         return self::$_pdo->lastInsertId(); $this->_todo->add('Task 2')     } );      }
  • 38. public function testFetchAll()     public function fetchAll() {     { $this->_todo->add('Task 1', 'm');         $query = 'SELECT * FROM todo'; $this->_todo->add('Task 2', 'f');         $stmt  = self::$_pdo ->query($query); $result = $this->_todo->fetchAll();         return $stmt $this->assertEquals( ->fetchAll(PDO::FETCH_ASSOC); 2,     } count($result) ); $this->assertContains( 'Task 1', $result[0] ); $this->assertContains( 'Task 2', $result[1] ); }
  • 39. public function testDone()     public function done($id) {     { $this->_todo->add('Task 1');         $query = 'UPDATE todo ' $this->_todo->add('Task 2');  . 'SET done = 'y''  . 'WHERE id = ?'; $this->assertEquals(         $stmt  = self::$_pdo->prepare($query); 1, $this->_todo->done(1)         $stmt->execute(array($id)); );         return $stmt->rowCount(); $this->assertEquals(     } 1, } $this->_todo->done(2) ); $this->assertEquals( 0, $this->_todo->done(3) ); } }
  • 53. <?php class InterfaceTest extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { $this->setBrowser("*chrome"); $this->setBrowserUrl("http://test.dev/"); } public function testMyTestCase() { $this->open("/advanced_php_testing/mvc/"); $this->type("id=new-todo", "Task 1"); $this->keyPress("id=new-todo", "13"); $this->waitForPageToLoad("30000"); $this->assertEquals("Task 1", $this->getText("//ul[@id='todo-list']/div[1]/div/div")); $this->type("id=new-todo", "Task 2"); $this->keyPress("id=new-todo", "13"); $this->waitForPageToLoad("30000"); $this->assertEquals("Task 2", $this->getText("//ul[@id='todo-list']/div[2]/div/div")); } }
  • 55. <?php class InterfaceTest extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { $this->_pdo = new PDO( $GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD']); $this->_pdo->query('TRUNCATE TABLE todo'); Todo::setDb($this->_pdo); $this->_todo = new Todo(); $this->setBrowser("*chrome"); $this->setBrowserUrl("http://test.dev/"); }
  • 69. <?php class Request { protected $_headers = array( 'REQUEST_METHOD' => 'GET', ); public function setHeader($name, $value) { $this->_headers[$name] = $value; } public function isPost() { return ('POST' === $this->_headers['REQUEST_METHOD']); } public function isAjax() { return ('XMLHttpRequest' === $this->_headers['X_REQUESTED_WITH']); }
  • 70. <?php class Request_Http extends Request { public function isPost() { return ('POST' === $_SERVER['REQUEST_METHOD']); } public function isAjax() { return ('XMLHttpRequest' === $_SERVER['X_REQUESTED_WITH']); } }
  • 72. <?php class Response { protected $_headers = array( 'Content-Type' => 'text/html; charset=utf-8', ); public function setHeader($name, $content) { $this->_headers[$name] = $content; } public function getHeader($name) { return isset($this->_headers[$name]) ? $this->_headers[$name] : null; } protected function sendHeaders() { // do nothing }
  • 74. $controller = new IndexController(new Todo()); $controller->setRequest(new Request_Http()) ->setResponse(new Response_Http()) ->sendResponse(true) ->dispatch(); $controller = new IndexController(new Todo()); $controller->setRequest(new Request()) ->setResponse(new Response()) ->dispatch();
  • 76. <?php class Test_ControllerTestCase extends PHPUnit_Framework_TestCase { protected $_controller = null; protected $_request = null; protected $_response = null; public function setUp() { $this->_controller->setRequest($this->_request) ->setResponse($this->_response); } public function dispatch($url) { $this->_parseUrl($url); $this->_controller->dispatch(); return $this; } protected function _parseUrl($url) { $urlInfo = parse_url($url); if (isset($urlInfo['query'])) { parse_str($urlInfo['query'], $_GET); } }
  • 78. <?php class IndexControllerTest extends Test_ControllerTestCase { public function setUp() { $todo = new Todo(); $this->_request = new Request(); $this->_response = new Response(); $this->_controller = new IndexController($todo); parent::setUp(); } public function tearDown() { $this->_request->reset(); $this->_response->reset(); } public function testHome() { $this->dispatch('/'); $this->assertAction('index') ->assertResponseCode(200); }
  • 82. <?php class IndexControllerTest extends Test_ControllerTestCase { public function setUp() { $todo = $this->_setUpTodo(); $this->_controller = new IndexController($todo); // ... } protected function _setUpTodo() { $todo = Phake::mock('Todo'); Phake::when($todo)->fetchAll()->thenReturn(array( array( 'id' => 1, 'task' => 'Task 1', 'done' => 'n', ), )); return $todo; }
  • 86. <?php class IndexControllerTest extends Test_ControllerTestCase { // ... public function testHome() { $this->dispatch('/'); $this->assertAction('index') ->assertResponseCode(200) ->assertQuery('#todo-list'); } public function testAdd() { $this->_request->setMethod('POST'); $_POST['task'] = 'Task 1'; $this->dispatch('/?act=add') ->assertAction('add') ->assertRedirectTo('./') ->assertResponseCode(200) ->assertQueryContain( '#todo-list>.todo>.display>.todo-text', 'Task 1' ); }
  • 90. ➡ ➡ ➡