Test-Driven Development
for TYPO3




Oliver Klee, 2011-12-13 and 2011-12-14
typo3-coding@oliverklee.de
Unit
tests?
Manual testing is cumbersome
Automated
testing is
fast
Unit tests for the
 Realty Manager
   extension
more than
1600 tests
in less than 60
    seconds
Verify that your code
does what you expect
Make sure that your
changes won‘t break
           anything
Keep
        other coders
from breaking your code
Don‘t break anything
even in complex projects
Create asafety net
   for refactoring
Green feels good!
Green feels good!
Know
   your
  tools
The phpunit extension
             has it all
The phpunit extension
               has it all
phpunit (TYPO3 extension)
The phpunit extension
               has it all
phpunit (TYPO3 extension)
 PHPUnit (PEAR package)
The phpunit extension
               has it all
phpunit (TYPO3 extension)
 PHPUnit (PEAR package)

 Testrunner
 (back-end-
  module)
The phpunit extension
               has it all
phpunit (TYPO3 extension)
 PHPUnit (PEAR package)

 Testrunner    Testrunner
 (back-end-
  module)     (CLI module)
The phpunit extension
               has it all
phpunit (TYPO3 extension)
 PHPUnit (PEAR package)
  Testing framework for FE & DB
 Testrunner         Testrunner
 (back-end-
  module)          (CLI module)
Let‘s get
some terms
  straight
Two tests
meet in a
  bar ...
Two tests
Test   meet in a
         bar ...
Two tests
  Test      meet in a
Assertion     bar ...
Two tests
  Test      meet in a
Assertion     bar ...
  Test
  Test
Two tests
  Test      meet in a
Assertion     bar ...
  Test
  Test
Test case
Two tests
  Test      meet in a
Assertion     bar ...
  Test
  Test
Test case
Test case
Two tests
  Test       meet in a
Assertion      bar ...
  Test
  Test
Test case
Test case
Test suite
Code   test-first
Code   test-first
Code   test-first

write
test
Code   test-first

write
test
Code    test-first

write          write
test           code
Code    test-first

write          write
test           code
Code    test-first

write          write
test           code
Code    test-first

write          write
test           code



                       refactor
Code    test-first

write          write
test           code



                       refactor
The   life cycle unit test
               of a
The   life cycle unit test
               of a
The   life cycle unit test
               of a
                      new FooTest();
The   life cycle unit test
               of a
                      new FooTest();
The   life cycle unit test
               of a
                      new FooTest();

                           setUp();
The   life cycle unit test
               of a
                      new FooTest();

                           setUp();

                      /** @test */
                      lifeIsGood();
The   life cycle unit test
               of a
                      new FooTest();

                           setUp();

                      /** @test */
                      lifeIsGood();
The   life cycle unit test
               of a
                      new FooTest();

                           setUp();

                      /** @test */
                      lifeIsGood();

                        tearDown();
The   life cycle unit test
               of a
                      new FooTest();

                           setUp();

                      /** @test */
                      lifeIsGood();

                        tearDown();
The   life cycle unit test
               of a
                      new FooTest();

                           setUp();

                      /** @test */
                      lifeIsGood();

                        tearDown();
Use   meaningful
           unit test   names
Use   meaningful
                          unit test   names
Name the
behavior.            classCanBeInstantiated
Use   meaningful
                            unit test   names
 Name the
 behavior.             classCanBeInstantiated


Mention the
 method.                   setTitleSetsTitle
Use   meaningful
                                 unit test   names
  Name the
  behavior.                 classCanBeInstantiated


Mention the
 method.                         setTitleSetsTitle


  Name the          setSizeWithZeroThrowsException
preconditions.   hasTitleForEmptyTitleReturnsFalse
Use   meaningful
                                 unit test   names
  Name the
  behavior.                 classCanBeInstantiated


Mention the
 method.                         setTitleSetsTitle


  Name the          setSizeWithZeroThrowsException
preconditions.   hasTitleForEmptyTitleReturnsFalse


  Dont‘t use
 "works" or
 "correctly".
Use   meaningful
                                   unit test   names
  Name the
  behavior.                   classCanBeInstantiated


Mention the
 method.                           setTitleSetsTitle


  Name the          setSizeWithZeroThrowsException
preconditions.   hasTitleForEmptyTitleReturnsFalse


  Dont‘t use
 "works" or             measureFrubbleWorksCorrectly
 "correctly".
Use   meaningful
                                   unit test   names
  Name the
  behavior.                   classCanBeInstantiated


Mention the
 method.                           setTitleSetsTitle


  Name the          setSizeWithZeroThrowsException
preconditions.   hasTitleForEmptyTitleReturnsFalse


  Dont‘t use
 "works" or             measureFrubbleWorksCorrectly
 "correctly".
Continuous
Integration
Continuous
Integration
    =
Continuous
Integration
    =
checking in
more often
The continuous integration server
                 monitors the code
     Checkin

                             Repository (SVN)
The continuous integration server
                 monitors the code
     Checkin



                hook
                             Repository (SVN)

               SVN
The continuous integration server
                     monitors the code
      Checkin



                   hook
                             Repository (SVN)

                  SVN



  continuous integration
         server
The continuous integration server
                     monitors the code
      Checkin



                    hook
                             Repository (SVN)

                   SVN
          Hey, a
         change!

  continuous integration
         server
The continuous integration server
                     monitors the code
      Checkin



                    hook
                                  Repository (SVN)

                   SVN
          Hey, a
         change!

  continuous integration   run the unit
         server             tests etc.
The continuous integration server
                     monitors the code
      Checkin



                    hook
                                  Repository (SVN)

                   SVN
          Hey, a
         change!

  continuous integration   run the unit   Report
         server             tests etc.
There are
 small and huge
              tests
Unit tests are
        small and fast
Integration tests test
  the complete thing
Automated click tests
    test the interface
Automated click tests
    test the interface



              Selenium
Blackbox tests
       test
        the   public interface
Whitebox tests   test the
       inner workings
The   testing framework
                 is created quickly
	   /**
	    * @var Tx_Phpunit_Framework
	    */
	   protected $testingFramework = NULL;

	   public function setUp() {
	   	 $this->testingFramework = new Tx_Phpunit_Framework('tx_news2');
	   }

	   public function tearDown() {
	   	 $this->testingFramework->cleanUp();
	   	 unset($this->testingFramework);
	   }
The   testing framework
                 is created quickly
	   /**
	    * @var Tx_Phpunit_Framework
	    */
	   protected $testingFramework = NULL;

	   public function setUp() {
	   	 $this->testingFramework = new Tx_Phpunit_Framework('tx_news2');
	   }
                                                       discard the FE,
	   public function tearDown() {
                                                     delete DB records,
	   	 $this->testingFramework->cleanUp();
	   	 unset($this->testingFramework);
                                                         delete files
	   }
The   testing framework
                 is created quickly
	   /**
	    * @var Tx_Phpunit_Framework
	    */
	   protected $testingFramework = NULL;

	   public function setUp() {
	   	 $this->testingFramework = new Tx_Phpunit_Framework('tx_news2');
	   }
                                                       discard the FE,
	   public function tearDown() {
                                                     delete DB records,
	   	 $this->testingFramework->cleanUp();
	   	 unset($this->testingFramework);
                                                         delete files
	   }




CREATE TABLE tx_news2_domain_model_news (
	 …
	 is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL,
	 …
The   testing framework
              can fake almost everything
The   testing framework
              can fake almost everything
         $recordUid = $tf->createRecord($tableName, array $recordData = array());
The   testing framework
              can fake almost everything
         $recordUid = $tf->createRecord($tableName, array $recordData = array());

                          $tf->changeRecord($tableName, $uid, array $recordData);
The   testing framework
              can fake almost everything
         $recordUid = $tf->createRecord($tableName, array $recordData = array());

                          $tf->changeRecord($tableName, $uid, array $recordData);


                                             $tf->deleteRecord($tableName, $uid);
The   testing framework
              can fake almost everything
         $recordUid = $tf->createRecord($tableName, array $recordData = array());

                          $tf->changeRecord($tableName, $uid, array $recordData);


                                             $tf->deleteRecord($tableName, $uid);


           $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);
The   testing framework
              can fake almost everything
             $recordUid = $tf->createRecord($tableName, array $recordData = array());

                              $tf->changeRecord($tableName, $uid, array $recordData);


                                                 $tf->deleteRecord($tableName, $uid);


               $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);


$tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName);
The   testing framework
              can fake almost everything
             $recordUid = $tf->createRecord($tableName, array $recordData = array());

                              $tf->changeRecord($tableName, $uid, array $recordData);


                                                 $tf->deleteRecord($tableName, $uid);


               $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);


$tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName);


                             $tf->removeRelation($tableName, $uidLocal, $uidForeign);
The   testing framework
              can fake almost everything
             $recordUid = $tf->createRecord($tableName, array $recordData = array());

                              $tf->changeRecord($tableName, $uid, array $recordData);


                                                 $tf->deleteRecord($tableName, $uid);


               $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);


$tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName);


                             $tf->removeRelation($tableName, $uidLocal, $uidForeign);


                 $numberOfRecords = $tf->countRecords($tableName, $whereClause = '');
The   testing framework
              can fake almost everything
             $recordUid = $tf->createRecord($tableName, array $recordData = array());

                              $tf->changeRecord($tableName, $uid, array $recordData);


                                                 $tf->deleteRecord($tableName, $uid);


               $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);


$tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName);


                             $tf->removeRelation($tableName, $uidLocal, $uidForeign);


                 $numberOfRecords = $tf->countRecords($tableName, $whereClause = '');


                         $success = $tf->existsRecord($tableName, $whereClause = '');
The   testing framework
              can fake almost everything
             $recordUid = $tf->createRecord($tableName, array $recordData = array());

                              $tf->changeRecord($tableName, $uid, array $recordData);


                                                 $tf->deleteRecord($tableName, $uid);


               $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);


$tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName);


                             $tf->removeRelation($tableName, $uidLocal, $uidForeign);


                 $numberOfRecords = $tf->countRecords($tableName, $whereClause = '');


                         $success = $tf->existsRecord($tableName, $whereClause = '');


               $success = $tf->existsExactlyOneRecord($tableName, $whereClause = '');
The   testing framework
              can fake almost everything
             $recordUid = $tf->createRecord($tableName, array $recordData = array());

                              $tf->changeRecord($tableName, $uid, array $recordData);


                                                 $tf->deleteRecord($tableName, $uid);


               $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);


$tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName);


                             $tf->removeRelation($tableName, $uidLocal, $uidForeign);


                 $numberOfRecords = $tf->countRecords($tableName, $whereClause = '');


                         $success = $tf->existsRecord($tableName, $whereClause = '');


               $success = $tf->existsExactlyOneRecord($tableName, $whereClause = '');


                              $success = $tf->existsRecordWithUid($tableName, $uid);
The   testing framework
              can fake almost everything
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                          $tf->createTemplate($pageId, array $recordData = array());
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                          $tf->createTemplate($pageId, array $recordData = array());


                                   $pageUid = $tf->createFakeFrontEnd($pageUid = 0);
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                          $tf->createTemplate($pageId, array $recordData = array());


                                   $pageUid = $tf->createFakeFrontEnd($pageUid = 0);


                                                         $tf->discardFakeFrontEnd();
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                          $tf->createTemplate($pageId, array $recordData = array());


                                   $pageUid = $tf->createFakeFrontEnd($pageUid = 0);


                                                         $tf->discardFakeFrontEnd();


              $groupUid = $tf->createFrontEndUserGroup(array $recordData = array());
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                          $tf->createTemplate($pageId, array $recordData = array());


                                   $pageUid = $tf->createFakeFrontEnd($pageUid = 0);


                                                         $tf->discardFakeFrontEnd();


              $groupUid = $tf->createFrontEndUserGroup(array $recordData = array());


      $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array());
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                          $tf->createTemplate($pageId, array $recordData = array());


                                   $pageUid = $tf->createFakeFrontEnd($pageUid = 0);


                                                         $tf->discardFakeFrontEnd();


              $groupUid = $tf->createFrontEndUserGroup(array $recordData = array());


      $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array());


                                                    $tf->loginFrontEndUser($userId);
The   testing framework
              can fake almost everything
      $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


      $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


 $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                          $tf->createTemplate($pageId, array $recordData = array());


                                   $pageUid = $tf->createFakeFrontEnd($pageUid = 0);


                                                         $tf->discardFakeFrontEnd();


              $groupUid = $tf->createFrontEndUserGroup(array $recordData = array());


      $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array());


              $tf->logoutFrontEndUser();            $tf->loginFrontEndUser($userId);
The   testing framework
              can fake almost everything
       $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


       $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


   $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                           $tf->createTemplate($pageId, array $recordData = array());


                                     $pageUid = $tf->createFakeFrontEnd($pageUid = 0);


                                                           $tf->discardFakeFrontEnd();


                $groupUid = $tf->createFrontEndUserGroup(array $recordData = array());


        $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array());


               $tf->logoutFrontEndUser();             $tf->loginFrontEndUser($userId);


$userUid = $tf->createAndLoginFrontEndUser($groups = '', array $recordData = array());
The   testing framework
              can fake almost everything
       $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());


       $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());


   $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());


                           $tf->createTemplate($pageId, array $recordData = array());


                                     $pageUid = $tf->createFakeFrontEnd($pageUid = 0);


                                                           $tf->discardFakeFrontEnd();


                $groupUid = $tf->createFrontEndUserGroup(array $recordData = array());


        $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array());


               $tf->logoutFrontEndUser();             $tf->loginFrontEndUser($userId);


$userUid = $tf->createAndLoginFrontEndUser($groups = '', array $recordData = array());


                                                      $isLoggedIn = $tf->isLoggedIn();
The   testing framework
              can fake almost everything
The   testing framework
              can fake almost everything
            $recordUid = $tf->createBackEndUser(array $recordData = array());
The   testing framework
              can fake almost everything
              $recordUid = $tf->createBackEndUser(array $recordData = array());

         $recordUid = $tf->createBackEndUserGroup(array $recordData = array());
The   testing framework
              can fake almost everything
The   testing framework
              can fake almost everything
          $path = $tf->createDummyFile($fileName = 'test.txt', $content = '');
The   testing framework
                can fake almost everything
                    $path = $tf->createDummyFile($fileName = 'test.txt', $content = '');


$path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array());
The   testing framework
                can fake almost everything
                    $path = $tf->createDummyFile($fileName = 'test.txt', $content = '');


$path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array());

                                                        $tf->deleteDummyFile($fileName);
The   testing framework
                can fake almost everything
                    $path = $tf->createDummyFile($fileName = 'test.txt', $content = '');


$path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array());

                                                        $tf->deleteDummyFile($fileName);


                                            $path = $tf->createDummyFolder($folderName);
The   testing framework
                can fake almost everything
                    $path = $tf->createDummyFile($fileName = 'test.txt', $content = '');


$path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array());

                                                        $tf->deleteDummyFile($fileName);


                                            $path = $tf->createDummyFolder($folderName);

                                                    $tf->deleteDummyFolder($folderName);
How to        your  test
      extbase                             controllers
class Tx_Coffee_Controller_CoffeeControllerTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
	    /** @var Tx_Coffee_Controller_CoffeeController */
	    protected $fixture;
	    /** @var Tx_Fluid_View_TemplateView */
	    protected $view = NULL;
	    /** @var Tx_Coffee_Domain_Repository_CoffeeRepository */
	    protected $coffeeRepository = NULL;

	   public function setUp() {
	   	    $this->fixture = new Tx_Coffee_Controller_CoffeeController();

	   	    $this->view = $this->getMock('Tx_Fluid_View_TemplateView', array(), array(), '', FALSE);
	   	    $this->fixture->setView($this->view);

	   	    $this->objectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface');
	   	    $this->fixture->injectObjectManager($this->objectManager);

	   	    $this->coffeeRepository = $this->getMock(
	   	    	    'Tx_Coffee_Domain_Repository_CoffeeRepository',
	   	    	    array('findAll', 'findByBrand'), array($this->objectManager)
	   	    );
	   	    $this->fixture->injectCoffeeRepository($this->coffeeRepository);
    }
How to        your  test
      extbase                             controllers
class Tx_Coffee_Controller_CoffeeControllerTest extends Tx_Extbase_Tests_Unit_BaseTestCase {
	    /** @var Tx_Coffee_Controller_CoffeeController */
	    protected $fixture;
	    /** @var Tx_Fluid_View_TemplateView */
	    protected $view = NULL;
	    /** @var Tx_Coffee_Domain_Repository_CoffeeRepository */
	    protected $coffeeRepository = NULL;

	   public function setUp() {
	   	    $this->fixture = new Tx_Coffee_Controller_CoffeeController();

	   	    $this->view = $this->getMock('Tx_Fluid_View_TemplateView', array(), array(), '', FALSE);
	   	    $this->fixture->setView($this->view);

	   	    $this->objectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface');
	   	    $this->fixture->injectObjectManager($this->objectManager);

	   	    $this->coffeeRepository = $this->getMock(
	   	    	    'Tx_Coffee_Domain_Repository_CoffeeRepository',
	   	    	    array('findAll', 'findByBrand'), array($this->objectManager)
	   	    );
	   	    $this->fixture->injectCoffeeRepository($this->coffeeRepository);
    }
                         class Tx_Coffee_Controller_CoffeeController extends Tx_Extbase_MVC_Controller_ActionController {
                         	    /**
                         	      * Sets the view.
                         	      *
                         	      * This function is intended to be used for unit testing purposes only.
                         	      *
                         	      * @param Tx_Fluid_View_TemplateView $view the new view
                         	      *
                         	      * @return void
                         	      */
                         	    public function setView(Tx_Fluid_View_TemplateView $view) {
                         	    	     $this->view = $view;
                         	    }
How to test   your
      extbase controllers
How to        your test
                 extbase                         controllers
/**
  * @test
  */
public function indexActionAssignsAllCoffeesToView() {
	    $models = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
	    $this->coffeeRepository->expects($this->once())->method('findAll')
	    	    ->will($this->returnValue($models));

	   $this->view->expects($this->at(0))->method('assign')->with('coffees', $models);

	   $this->fixture->indexAction();
}
How to        your test
                 extbase                         controllers
/**
  * @test
  */
public function indexActionAssignsAllCoffeesToView() {
	    $models = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface');
	    $this->coffeeRepository->expects($this->once())->method('findAll')
	    	    ->will($this->returnValue($models));

	   $this->view->expects($this->at(0))->method('assign')->with('coffees', $models);

	   $this->fixture->indexAction();
}




/**
  * @test
  */
public function showActionAssignsModelToView() {
	    $model = clone new Tx_Coffee_Domain_Model_Coffee();
	    $this->view->expects($this->at(0))->method('assign')->with('coffee', $model);

	   $this->fixture->showAction($model);
}

Test-Driven Development for TYPO3

  • 1.
    Test-Driven Development for TYPO3 OliverKlee, 2011-12-13 and 2011-12-14 typo3-coding@oliverklee.de
  • 2.
  • 3.
  • 4.
  • 5.
    Unit tests forthe Realty Manager extension
  • 6.
  • 7.
    in less than60 seconds
  • 8.
    Verify that yourcode does what you expect
  • 9.
    Make sure thatyour changes won‘t break anything
  • 10.
    Keep other coders from breaking your code
  • 11.
    Don‘t break anything evenin complex projects
  • 12.
    Create asafety net for refactoring
  • 13.
  • 14.
  • 15.
    Know your tools
  • 16.
  • 17.
    The phpunit extension has it all phpunit (TYPO3 extension)
  • 18.
    The phpunit extension has it all phpunit (TYPO3 extension) PHPUnit (PEAR package)
  • 19.
    The phpunit extension has it all phpunit (TYPO3 extension) PHPUnit (PEAR package) Testrunner (back-end- module)
  • 20.
    The phpunit extension has it all phpunit (TYPO3 extension) PHPUnit (PEAR package) Testrunner Testrunner (back-end- module) (CLI module)
  • 21.
    The phpunit extension has it all phpunit (TYPO3 extension) PHPUnit (PEAR package) Testing framework for FE & DB Testrunner Testrunner (back-end- module) (CLI module)
  • 22.
  • 23.
  • 24.
    Two tests Test meet in a bar ...
  • 25.
    Two tests Test meet in a Assertion bar ...
  • 26.
    Two tests Test meet in a Assertion bar ... Test Test
  • 27.
    Two tests Test meet in a Assertion bar ... Test Test Test case
  • 28.
    Two tests Test meet in a Assertion bar ... Test Test Test case Test case
  • 29.
    Two tests Test meet in a Assertion bar ... Test Test Test case Test case Test suite
  • 30.
    Code test-first
  • 31.
    Code test-first
  • 32.
    Code test-first write test
  • 33.
    Code test-first write test
  • 34.
    Code test-first write write test code
  • 35.
    Code test-first write write test code
  • 36.
    Code test-first write write test code
  • 37.
    Code test-first write write test code refactor
  • 38.
    Code test-first write write test code refactor
  • 39.
    The life cycle unit test of a
  • 40.
    The life cycle unit test of a
  • 41.
    The life cycle unit test of a new FooTest();
  • 42.
    The life cycle unit test of a new FooTest();
  • 43.
    The life cycle unit test of a new FooTest(); setUp();
  • 44.
    The life cycle unit test of a new FooTest(); setUp(); /** @test */ lifeIsGood();
  • 45.
    The life cycle unit test of a new FooTest(); setUp(); /** @test */ lifeIsGood();
  • 46.
    The life cycle unit test of a new FooTest(); setUp(); /** @test */ lifeIsGood(); tearDown();
  • 47.
    The life cycle unit test of a new FooTest(); setUp(); /** @test */ lifeIsGood(); tearDown();
  • 48.
    The life cycle unit test of a new FooTest(); setUp(); /** @test */ lifeIsGood(); tearDown();
  • 49.
    Use meaningful unit test names
  • 50.
    Use meaningful unit test names Name the behavior. classCanBeInstantiated
  • 51.
    Use meaningful unit test names Name the behavior. classCanBeInstantiated Mention the method. setTitleSetsTitle
  • 52.
    Use meaningful unit test names Name the behavior. classCanBeInstantiated Mention the method. setTitleSetsTitle Name the setSizeWithZeroThrowsException preconditions. hasTitleForEmptyTitleReturnsFalse
  • 53.
    Use meaningful unit test names Name the behavior. classCanBeInstantiated Mention the method. setTitleSetsTitle Name the setSizeWithZeroThrowsException preconditions. hasTitleForEmptyTitleReturnsFalse Dont‘t use "works" or "correctly".
  • 54.
    Use meaningful unit test names Name the behavior. classCanBeInstantiated Mention the method. setTitleSetsTitle Name the setSizeWithZeroThrowsException preconditions. hasTitleForEmptyTitleReturnsFalse Dont‘t use "works" or measureFrubbleWorksCorrectly "correctly".
  • 55.
    Use meaningful unit test names Name the behavior. classCanBeInstantiated Mention the method. setTitleSetsTitle Name the setSizeWithZeroThrowsException preconditions. hasTitleForEmptyTitleReturnsFalse Dont‘t use "works" or measureFrubbleWorksCorrectly "correctly".
  • 56.
  • 57.
  • 58.
    Continuous Integration = checking in more often
  • 59.
    The continuous integrationserver monitors the code Checkin Repository (SVN)
  • 60.
    The continuous integrationserver monitors the code Checkin hook Repository (SVN) SVN
  • 61.
    The continuous integrationserver monitors the code Checkin hook Repository (SVN) SVN continuous integration server
  • 62.
    The continuous integrationserver monitors the code Checkin hook Repository (SVN) SVN Hey, a change! continuous integration server
  • 63.
    The continuous integrationserver monitors the code Checkin hook Repository (SVN) SVN Hey, a change! continuous integration run the unit server tests etc.
  • 64.
    The continuous integrationserver monitors the code Checkin hook Repository (SVN) SVN Hey, a change! continuous integration run the unit Report server tests etc.
  • 65.
    There are smalland huge tests
  • 66.
    Unit tests are small and fast
  • 67.
    Integration tests test the complete thing
  • 68.
    Automated click tests test the interface
  • 69.
    Automated click tests test the interface Selenium
  • 70.
    Blackbox tests test the public interface
  • 71.
    Whitebox tests test the inner workings
  • 72.
    The testing framework is created quickly /** * @var Tx_Phpunit_Framework */ protected $testingFramework = NULL; public function setUp() { $this->testingFramework = new Tx_Phpunit_Framework('tx_news2'); } public function tearDown() { $this->testingFramework->cleanUp(); unset($this->testingFramework); }
  • 73.
    The testing framework is created quickly /** * @var Tx_Phpunit_Framework */ protected $testingFramework = NULL; public function setUp() { $this->testingFramework = new Tx_Phpunit_Framework('tx_news2'); } discard the FE, public function tearDown() { delete DB records, $this->testingFramework->cleanUp(); unset($this->testingFramework); delete files }
  • 74.
    The testing framework is created quickly /** * @var Tx_Phpunit_Framework */ protected $testingFramework = NULL; public function setUp() { $this->testingFramework = new Tx_Phpunit_Framework('tx_news2'); } discard the FE, public function tearDown() { delete DB records, $this->testingFramework->cleanUp(); unset($this->testingFramework); delete files } CREATE TABLE tx_news2_domain_model_news ( … is_dummy_record tinyint(1) unsigned DEFAULT '0' NOT NULL, …
  • 75.
    The testing framework can fake almost everything
  • 76.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array());
  • 77.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData);
  • 78.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid);
  • 79.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid); $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0);
  • 80.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid); $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0); $tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName);
  • 81.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid); $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0); $tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName); $tf->removeRelation($tableName, $uidLocal, $uidForeign);
  • 82.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid); $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0); $tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName); $tf->removeRelation($tableName, $uidLocal, $uidForeign); $numberOfRecords = $tf->countRecords($tableName, $whereClause = '');
  • 83.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid); $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0); $tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName); $tf->removeRelation($tableName, $uidLocal, $uidForeign); $numberOfRecords = $tf->countRecords($tableName, $whereClause = ''); $success = $tf->existsRecord($tableName, $whereClause = '');
  • 84.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid); $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0); $tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName); $tf->removeRelation($tableName, $uidLocal, $uidForeign); $numberOfRecords = $tf->countRecords($tableName, $whereClause = ''); $success = $tf->existsRecord($tableName, $whereClause = ''); $success = $tf->existsExactlyOneRecord($tableName, $whereClause = '');
  • 85.
    The testing framework can fake almost everything $recordUid = $tf->createRecord($tableName, array $recordData = array()); $tf->changeRecord($tableName, $uid, array $recordData); $tf->deleteRecord($tableName, $uid); $tf->createRelation($tableName, $uidLocal, $uidForeign, $sorting = 0); $tf->createRelationAndUpdateCounter($tableName, $uidLocal, $uidForeign, $columnName); $tf->removeRelation($tableName, $uidLocal, $uidForeign); $numberOfRecords = $tf->countRecords($tableName, $whereClause = ''); $success = $tf->existsRecord($tableName, $whereClause = ''); $success = $tf->existsExactlyOneRecord($tableName, $whereClause = ''); $success = $tf->existsRecordWithUid($tableName, $uid);
  • 86.
    The testing framework can fake almost everything
  • 87.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array());
  • 88.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array());
  • 89.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array());
  • 90.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array());
  • 91.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0);
  • 92.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0); $tf->discardFakeFrontEnd();
  • 93.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0); $tf->discardFakeFrontEnd(); $groupUid = $tf->createFrontEndUserGroup(array $recordData = array());
  • 94.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0); $tf->discardFakeFrontEnd(); $groupUid = $tf->createFrontEndUserGroup(array $recordData = array()); $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array());
  • 95.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0); $tf->discardFakeFrontEnd(); $groupUid = $tf->createFrontEndUserGroup(array $recordData = array()); $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array()); $tf->loginFrontEndUser($userId);
  • 96.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0); $tf->discardFakeFrontEnd(); $groupUid = $tf->createFrontEndUserGroup(array $recordData = array()); $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array()); $tf->logoutFrontEndUser(); $tf->loginFrontEndUser($userId);
  • 97.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0); $tf->discardFakeFrontEnd(); $groupUid = $tf->createFrontEndUserGroup(array $recordData = array()); $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array()); $tf->logoutFrontEndUser(); $tf->loginFrontEndUser($userId); $userUid = $tf->createAndLoginFrontEndUser($groups = '', array $recordData = array());
  • 98.
    The testing framework can fake almost everything $pageUid = $tf->createFrontEndPage($parentId = 0, array $recordData = array()); $pageUid = $tf->createSystemFolder($parentId = 0, array $recordData = array()); $elementUid = $tf->createContentElement($pageId = 0, array $recordData = array()); $tf->createTemplate($pageId, array $recordData = array()); $pageUid = $tf->createFakeFrontEnd($pageUid = 0); $tf->discardFakeFrontEnd(); $groupUid = $tf->createFrontEndUserGroup(array $recordData = array()); $userUid = $tf->createFrontEndUser($groups = '', array $recordData = array()); $tf->logoutFrontEndUser(); $tf->loginFrontEndUser($userId); $userUid = $tf->createAndLoginFrontEndUser($groups = '', array $recordData = array()); $isLoggedIn = $tf->isLoggedIn();
  • 99.
    The testing framework can fake almost everything
  • 100.
    The testing framework can fake almost everything $recordUid = $tf->createBackEndUser(array $recordData = array());
  • 101.
    The testing framework can fake almost everything $recordUid = $tf->createBackEndUser(array $recordData = array()); $recordUid = $tf->createBackEndUserGroup(array $recordData = array());
  • 102.
    The testing framework can fake almost everything
  • 103.
    The testing framework can fake almost everything $path = $tf->createDummyFile($fileName = 'test.txt', $content = '');
  • 104.
    The testing framework can fake almost everything $path = $tf->createDummyFile($fileName = 'test.txt', $content = ''); $path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array());
  • 105.
    The testing framework can fake almost everything $path = $tf->createDummyFile($fileName = 'test.txt', $content = ''); $path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array()); $tf->deleteDummyFile($fileName);
  • 106.
    The testing framework can fake almost everything $path = $tf->createDummyFile($fileName = 'test.txt', $content = ''); $path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array()); $tf->deleteDummyFile($fileName); $path = $tf->createDummyFolder($folderName);
  • 107.
    The testing framework can fake almost everything $path = $tf->createDummyFile($fileName = 'test.txt', $content = ''); $path = $tf->createDummyZipArchive($fileName = 'test.zip', array $filesToAdd = array()); $tf->deleteDummyFile($fileName); $path = $tf->createDummyFolder($folderName); $tf->deleteDummyFolder($folderName);
  • 108.
    How to your test extbase controllers class Tx_Coffee_Controller_CoffeeControllerTest extends Tx_Extbase_Tests_Unit_BaseTestCase { /** @var Tx_Coffee_Controller_CoffeeController */ protected $fixture; /** @var Tx_Fluid_View_TemplateView */ protected $view = NULL; /** @var Tx_Coffee_Domain_Repository_CoffeeRepository */ protected $coffeeRepository = NULL; public function setUp() { $this->fixture = new Tx_Coffee_Controller_CoffeeController(); $this->view = $this->getMock('Tx_Fluid_View_TemplateView', array(), array(), '', FALSE); $this->fixture->setView($this->view); $this->objectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface'); $this->fixture->injectObjectManager($this->objectManager); $this->coffeeRepository = $this->getMock( 'Tx_Coffee_Domain_Repository_CoffeeRepository', array('findAll', 'findByBrand'), array($this->objectManager) ); $this->fixture->injectCoffeeRepository($this->coffeeRepository); }
  • 109.
    How to your test extbase controllers class Tx_Coffee_Controller_CoffeeControllerTest extends Tx_Extbase_Tests_Unit_BaseTestCase { /** @var Tx_Coffee_Controller_CoffeeController */ protected $fixture; /** @var Tx_Fluid_View_TemplateView */ protected $view = NULL; /** @var Tx_Coffee_Domain_Repository_CoffeeRepository */ protected $coffeeRepository = NULL; public function setUp() { $this->fixture = new Tx_Coffee_Controller_CoffeeController(); $this->view = $this->getMock('Tx_Fluid_View_TemplateView', array(), array(), '', FALSE); $this->fixture->setView($this->view); $this->objectManager = $this->getMock('Tx_Extbase_Object_ObjectManagerInterface'); $this->fixture->injectObjectManager($this->objectManager); $this->coffeeRepository = $this->getMock( 'Tx_Coffee_Domain_Repository_CoffeeRepository', array('findAll', 'findByBrand'), array($this->objectManager) ); $this->fixture->injectCoffeeRepository($this->coffeeRepository); } class Tx_Coffee_Controller_CoffeeController extends Tx_Extbase_MVC_Controller_ActionController { /** * Sets the view. * * This function is intended to be used for unit testing purposes only. * * @param Tx_Fluid_View_TemplateView $view the new view * * @return void */ public function setView(Tx_Fluid_View_TemplateView $view) { $this->view = $view; }
  • 110.
    How to test your extbase controllers
  • 111.
    How to your test extbase controllers /** * @test */ public function indexActionAssignsAllCoffeesToView() { $models = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface'); $this->coffeeRepository->expects($this->once())->method('findAll') ->will($this->returnValue($models)); $this->view->expects($this->at(0))->method('assign')->with('coffees', $models); $this->fixture->indexAction(); }
  • 112.
    How to your test extbase controllers /** * @test */ public function indexActionAssignsAllCoffeesToView() { $models = $this->getMock('Tx_Extbase_Persistence_QueryResultInterface'); $this->coffeeRepository->expects($this->once())->method('findAll') ->will($this->returnValue($models)); $this->view->expects($this->at(0))->method('assign')->with('coffees', $models); $this->fixture->indexAction(); } /** * @test */ public function showActionAssignsModelToView() { $model = clone new Tx_Coffee_Domain_Model_Coffee(); $this->view->expects($this->at(0))->method('assign')->with('coffee', $model); $this->fixture->showAction($model); }