SlideShare a Scribd company logo
1 of 92
Download to read offline
watch -n 15 -d 
   find tests/ -mmin -1 -iname '"*.php"' -exec 
   'phpunit -c tests/phpunit.xml {} ;'
➡
➡
➡
➡
library
!"" Controller.php
!"" Response.php
!"" Request.php
!"" View.php
#
!"" Request
#   $"" Http.php
!"" Response
#   $"" Http.php
!"" Test
#   $"" ControllerTestCase.php
$"" View
     $"" Html.php
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
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';
<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)
<?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)
        );
    }
}
➡	 
➡
➡
➡
➡
➡
<?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"));
    }
}
<?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/");
    }
<?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']);
    }
}
<?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
    }
$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();
<?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);
    }
<?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;
    }
➡ assertQuery($selector)
➡ assertQueryContain($selector, $text)
<?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

More Related Content

What's hot

Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolveXSolve
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data ObjectsWez Furlong
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitmfrost503
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128PrinceGuru MS
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & RESTHugo Hamon
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm OldRoss Tuck
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5 Wildan Maulana
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2zfconfua
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにYuya Takeyama
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в MagentoMagecom Ukraine
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien Potencier
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP GeneratorsMark Baker
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Fabien Potencier
 

What's hot (20)

Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Php tips-and-tricks4128
Php tips-and-tricks4128Php tips-and-tricks4128
Php tips-and-tricks4128
 
Silex meets SOAP & REST
Silex meets SOAP & RESTSilex meets SOAP & REST
Silex meets SOAP & REST
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm Old
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
 
Doctrine 2
Doctrine 2Doctrine 2
Doctrine 2
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3Dependency Injection with PHP and PHP 5.3
Dependency Injection with PHP and PHP 5.3
 

Viewers also liked

PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹Jace Ju
 
Refactoring with Patterns in PHP
Refactoring with Patterns in PHPRefactoring with Patterns in PHP
Refactoring with Patterns in PHPJace Ju
 
第一次用 PHPUnit 寫測試就上手
第一次用 PHPUnit 寫測試就上手第一次用 PHPUnit 寫測試就上手
第一次用 PHPUnit 寫測試就上手Yi-Ming Huang
 
PHP 防駭 - 基礎觀念篇
PHP 防駭 - 基礎觀念篇PHP 防駭 - 基礎觀念篇
PHP 防駭 - 基礎觀念篇Jace Ju
 
Php Security By Mugdha And Anish
Php Security By Mugdha And AnishPhp Security By Mugdha And Anish
Php Security By Mugdha And AnishOSSCube
 
PHP Advanced
PHP AdvancedPHP Advanced
PHP AdvancedNoveo
 
Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010Michelangelo van Dam
 
Advanced PHP Web Development Tools in 2015
Advanced PHP Web Development Tools in 2015Advanced PHP Web Development Tools in 2015
Advanced PHP Web Development Tools in 2015iScripts
 
PHP 物件導向 - 基礎觀念篇
PHP 物件導向 - 基礎觀念篇PHP 物件導向 - 基礎觀念篇
PHP 物件導向 - 基礎觀念篇Jace Ju
 
What happens in laravel 4 bootstraping
What happens in laravel 4 bootstrapingWhat happens in laravel 4 bootstraping
What happens in laravel 4 bootstrapingJace Ju
 
Advanced PHP: Design Patterns - Dennis-Jan Broerse
Advanced PHP: Design Patterns - Dennis-Jan BroerseAdvanced PHP: Design Patterns - Dennis-Jan Broerse
Advanced PHP: Design Patterns - Dennis-Jan Broersedpc
 
Introduction to PHP
Introduction to PHPIntroduction to PHP
Introduction to PHPBradley Holt
 
PHP Powerpoint -- Teach PHP with this
PHP Powerpoint -- Teach PHP with thisPHP Powerpoint -- Teach PHP with this
PHP Powerpoint -- Teach PHP with thisIan Macali
 

Viewers also liked (17)

PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹
 
Refactoring with Patterns in PHP
Refactoring with Patterns in PHPRefactoring with Patterns in PHP
Refactoring with Patterns in PHP
 
第一次用 PHPUnit 寫測試就上手
第一次用 PHPUnit 寫測試就上手第一次用 PHPUnit 寫測試就上手
第一次用 PHPUnit 寫測試就上手
 
PHP 防駭 - 基礎觀念篇
PHP 防駭 - 基礎觀念篇PHP 防駭 - 基礎觀念篇
PHP 防駭 - 基礎觀念篇
 
Php Security By Mugdha And Anish
Php Security By Mugdha And AnishPhp Security By Mugdha And Anish
Php Security By Mugdha And Anish
 
PHP Advanced
PHP AdvancedPHP Advanced
PHP Advanced
 
Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010
 
Advanced PHP Simplified
Advanced PHP SimplifiedAdvanced PHP Simplified
Advanced PHP Simplified
 
Advanced PHP Web Development Tools in 2015
Advanced PHP Web Development Tools in 2015Advanced PHP Web Development Tools in 2015
Advanced PHP Web Development Tools in 2015
 
PHP 物件導向 - 基礎觀念篇
PHP 物件導向 - 基礎觀念篇PHP 物件導向 - 基礎觀念篇
PHP 物件導向 - 基礎觀念篇
 
What happens in laravel 4 bootstraping
What happens in laravel 4 bootstrapingWhat happens in laravel 4 bootstraping
What happens in laravel 4 bootstraping
 
DIWE - Advanced PHP Concepts
DIWE - Advanced PHP ConceptsDIWE - Advanced PHP Concepts
DIWE - Advanced PHP Concepts
 
Advanced PHP: Design Patterns - Dennis-Jan Broerse
Advanced PHP: Design Patterns - Dennis-Jan BroerseAdvanced PHP: Design Patterns - Dennis-Jan Broerse
Advanced PHP: Design Patterns - Dennis-Jan Broerse
 
PHP Web Programming
PHP Web ProgrammingPHP Web Programming
PHP Web Programming
 
Introduction to PHP
Introduction to PHPIntroduction to PHP
Introduction to PHP
 
PHP Powerpoint -- Teach PHP with this
PHP Powerpoint -- Teach PHP with thisPHP Powerpoint -- Teach PHP with this
PHP Powerpoint -- Teach PHP with this
 
Php Presentation
Php PresentationPhp Presentation
Php Presentation
 

Similar to Advanced php testing in action

Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitmfrost503
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11Michelangelo van Dam
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPWildan Maulana
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
R57shell
R57shellR57shell
R57shellady36
 
Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"Fwdays
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011Alessandro Nadalin
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 

Similar to Advanced php testing in action (20)

Workshop unittesting
Workshop unittestingWorkshop unittesting
Workshop unittesting
 
Presentation1
Presentation1Presentation1
Presentation1
 
Oops in php
Oops in phpOops in php
Oops in php
 
Mocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnitMocking Dependencies in PHPUnit
Mocking Dependencies in PHPUnit
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11Unit testing with zend framework tek11
Unit testing with zend framework tek11
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOP
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
R57shell
R57shellR57shell
R57shell
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
PHPSpec BDD for PHP
PHPSpec BDD for PHPPHPSpec BDD for PHP
PHPSpec BDD for PHP
 
linieaire regressie
linieaire regressielinieaire regressie
linieaire regressie
 
Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"Pim Elshoff "Technically DDD"
Pim Elshoff "Technically DDD"
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 

More from Jace Ju

深入淺出 MVC
深入淺出 MVC深入淺出 MVC
深入淺出 MVCJace Ju
 
如何打造 WebMVC Framework - 基礎概念篇
如何打造 WebMVC Framework - 基礎概念篇如何打造 WebMVC Framework - 基礎概念篇
如何打造 WebMVC Framework - 基礎概念篇Jace Ju
 
Patterns in Library Design (套件設計裡的模式)
Patterns in Library Design (套件設計裡的模式)Patterns in Library Design (套件設計裡的模式)
Patterns in Library Design (套件設計裡的模式)Jace Ju
 
Patterns in Zend Framework
Patterns in Zend FrameworkPatterns in Zend Framework
Patterns in Zend FrameworkJace Ju
 
Head First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & ApplicationHead First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & ApplicationJace Ju
 
常見設計模式介紹
常見設計模式介紹常見設計模式介紹
常見設計模式介紹Jace Ju
 
Web Refactoring
Web RefactoringWeb Refactoring
Web RefactoringJace Ju
 
jQuery 實戰經驗講座
jQuery 實戰經驗講座jQuery 實戰經驗講座
jQuery 實戰經驗講座Jace Ju
 
CSS 排版 - 基礎觀念篇
CSS 排版 - 基礎觀念篇CSS 排版 - 基礎觀念篇
CSS 排版 - 基礎觀念篇Jace Ju
 

More from Jace Ju (9)

深入淺出 MVC
深入淺出 MVC深入淺出 MVC
深入淺出 MVC
 
如何打造 WebMVC Framework - 基礎概念篇
如何打造 WebMVC Framework - 基礎概念篇如何打造 WebMVC Framework - 基礎概念篇
如何打造 WebMVC Framework - 基礎概念篇
 
Patterns in Library Design (套件設計裡的模式)
Patterns in Library Design (套件設計裡的模式)Patterns in Library Design (套件設計裡的模式)
Patterns in Library Design (套件設計裡的模式)
 
Patterns in Zend Framework
Patterns in Zend FrameworkPatterns in Zend Framework
Patterns in Zend Framework
 
Head First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & ApplicationHead First Zend Framework - Part 1 Project & Application
Head First Zend Framework - Part 1 Project & Application
 
常見設計模式介紹
常見設計模式介紹常見設計模式介紹
常見設計模式介紹
 
Web Refactoring
Web RefactoringWeb Refactoring
Web Refactoring
 
jQuery 實戰經驗講座
jQuery 實戰經驗講座jQuery 實戰經驗講座
jQuery 實戰經驗講座
 
CSS 排版 - 基礎觀念篇
CSS 排版 - 基礎觀念篇CSS 排版 - 基礎觀念篇
CSS 排版 - 基礎觀念篇
 

Recently uploaded

(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...AliaaTarek5
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 

Recently uploaded (20)

(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
(How to Program) Paul Deitel, Harvey Deitel-Java How to Program, Early Object...
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 

Advanced php testing in action

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6. watch -n 15 -d find tests/ -mmin -1 -iname '"*.php"' -exec 'phpunit -c tests/phpunit.xml {} ;'
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23. library !"" Controller.php !"" Response.php !"" Request.php !"" View.php # !"" Request #   $"" Http.php !"" Response #   $"" Http.php !"" Test #   $"" ControllerTestCase.php $"" View    $"" Html.php
  • 24.
  • 25.
  • 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
  • 27.
  • 28.
  • 29.
  • 30.
  • 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';
  • 32.
  • 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>
  • 35.
  • 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) ); } }
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 48.
  • 49.
  • 50.
  • 52.
  • 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")); } }
  • 54.
  • 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/"); }
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 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']); } }
  • 71.
  • 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 }
  • 73.
  • 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();
  • 75.
  • 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); }
  • 79.
  • 80.
  • 81.
  • 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; }
  • 83.
  • 85.
  • 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' ); }
  • 87.
  • 89.
  • 90. ➡ ➡ ➡