Quality assurance for php projects with PHPStorm
-
Upload
michelangelo-van-dam -
Category
Technology
-
view
122 -
download
5
description
Transcript of Quality assurance for php projects with PHPStorm
QA for PHP projectsusing PHPStorm
JetBrains Webinar, April 25 2013
2
Michelangelo van Dam
Goals
3
• improve QA in your PHP projects• deliver higher quality of applicaIons• become familiarized with available tools
Our host for this webinar
4
Why Quality Assurance
5
6
Safeguarding code
7
Detect bugs early
8
Observe behaviour
9
Prevent accidents
10
Tracking progress
Let’s get our hands dirty
11
Revision Control
12
13
FTP
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 like JetBrain’s IDE- analytical tools
TIP: hooks for tools
PHP Lint
15
PHP Lint
16
• 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
Running on command line
17
SCM commit hook
18
#!/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
No syntax failures
19
PHPStorm syntax checking
20
DocumentaIon
21
Why documenIng?
22
• new members in the team• working with remote workers• analyzing improvements• think before doing• used by IDE’s and editors for code hinIng ;-‐)
PHPDocumentor2
23
Class details
24
Uses docblock in code
25
Class graphs
26
Debugging
27
The art of finding a bug
28
• Debugging allows you to walk step-‐by-‐step through your code base unIl you reach the point of failure.
XDebug php.ini se`ngs[xdebug]zend_extension=/usr/lib/php/extensions/xdebug.soxdebug.default_enable=1xdebug.cli_color=1xdebug.remote_enable=onxdebug.remote_connect_back=1xdebug.remote_handler=dbgpxdebug.remote_host=127.0.0.1xdebug.remote_port=9000xdebug.scream=1
29
Debugging in PHPStorm
30
TesIng
31
Most common excuses
32
• no Ime• not within budget• development team does not know how• tests are provided aaer delivery• …
NO EXCUSE!
33
Benefits of tesIng
34
• beder code with smaller footprint• allows refactoring• detects bugs in an early stage• saves Ime in maintenance stage
Se`ng things up
35
ConfiguraIon: phpunit.xml
36
<phpunit bootstrap="./Bootstrap.php">
<testsuite name="Unit test suite"> <directory>./</directory> </testsuite>
<filter> <whitelist> <directory suffix=".php">../application/</directory> <directory suffix=".php">../library/</directory> </whitelist> </filter>
</phpunit>
Bootstrapping app<?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();
37
WriIng tests
38
TesIng a class
39
WriIng a test
40
<?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()); }}
WriIng the class<?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(), ); }}
41
Adding validaIonprotected $_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); }}
42
Modify seders & gederspublic 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;}
43
Modify seders & geders 2public 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;}
44
Modify geders & seders 3public 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;}
45
Running tests
46
Or in PHPStorm
47
Mess DetecIon
48
Mess DetecIon
49
• code smells• possible bugs• sub-‐opImal code• over complicated expressions• unused parameters, methods and properIes• wrongly named parameters, methods or properIes
Running on command line
50
Running in PHPStorm
51
AutomaIon
52
Key reason
53
“computers are great at doing repetitive tasks very well”
AutomaIon
54
• Limit risk of human error•Will always be executed in same order• Can be shared amongst team members• Allows to fine-‐tune and improve features
55
AutomaIon with Phing
Running Phing on CLI
56
Running in PHPStorm
57
Summary
58
Overview of tools
59
• SCM (SVN, GIT, …)• PHP Lint• PHP Document Generator• Debugging• PHPUnit TesIng• PHP Mess detecIon• Phing automaIon
}
Quality Assurance
• is part of development process• will only work if the tools are available• and developers see the benefits of QA
60
PHPStorm IDE
61
Contact
62
Michelangelo van DamZend Certified Engineer
email: [email protected]: michelangelovandamtwitter: @DragonBe
tel EU: +32 15 34 52 90tel US: 202 559-7401
www.in2it.be
facebook.com/in2itvof | @in2itvof
Contact us forConsultancy - Training - QA - Webdesign
Credits
I’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/4115844000file cabinet: http://www.flickr.com/photos/manc/1427691715documentation: http://www.flickr.com/photos/dennis_matheson/3269442687exam: http://www.flickr.com/photos/albertogp123/5843577306dead roach: http://www.flickr.com/photos/stevensnodgrass/7504408776garbage: http://www.flickr.com/photos/amstersam/4608512202gears: http://www.flickr.com/photos/freefoto/5982549938elephpant: http://www.flickr.com/photos/drewm/3191872515
Fork this code
http://github.com/DragonBe/zftest
64
Thank you
65