Quality Assurance in PHP Projects

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

1 comments

Comments 1 - 1 of 1 previous next Post a comment

  • + avinashb1 avinashb1 9 months ago
    This is a very good N Gr8 for all user n very useful to all
    Avinash B.
Post a comment
Embed Video
Edit your comment Cancel

13 Favorites, 2 Groups & 4 Events

Quality Assurance in PHP Projects - Presentation Transcript

  1. QA in PHP Projects Sebastian Bergmann http://thePHP.cc/ http://QualityAssuranceInPHPProjects.com/ March 18th 2009
  2. Who I Am Sebastian Bergmann  Involved in the PHP  project since 2000 Creator of PHPUnit  Co-Founder and  Principal Consultant with thePHP.cc
  3. What is great Software? The customer-friendly programmer says:  ”Great software always does what the customer wants it to. So even if customers think of new ways to use the software, it doesn't break or give them unexpected results.” This slide contains material from ”Head First Object-Oriented Analysis & Design”, O'Reilly, 2006
  4. What is great Software? The object-oriented programmer says:  ”Great software is code that is object-oriented. So there's not a bunch of duplicated code, and each object pretty much controls its own behaviour. It's also easy to extend because your design is really solid and flexible.” This slide contains material from ”Head First Object-Oriented Analysis & Design”, O'Reilly, 2006
  5. What is great Software? The design-guru programmer says:  ”Great software is when you use tried-and-true design patterns and principles. You've kept your objects loosely coupled, and your code open for extension but closed for modification. That also helps make the code more reusable, so you don't have to rework everything to use parts of your application over and over again.” This slide contains material from ”Head First Object-Oriented Analysis & Design”, O'Reilly, 2006
  6. Aspects of Software Quality Good Code Security   Few Branches Robustness   Few Dependencies Stability   Locality of Change  Performance  Small Blocks  Scalability  Self-Explanatory  Usability  Testable 
  7. When things go wrong ...
  8. Why did I not test this?
  9. Testing Web Applications End-to-End Testing Static Analysis of HTML does not work  Instead: Test web applications in the  browser
  10. End-to-End Testing Manual Testing Not automated, slow and expensive  Complete application must be ready  before it can be tested Tests need to be repeated  when the application changes
  11. End-to-End Testing Automated Testing Test results  are deterministic,  automatically evaluated  and do not have to be interpreted  by a human tester Tests are repeatable without additional  costs
  12. End-to-End Testing Selenium Selenium  Test web applications in a web browser  Selenium IDE  Extension for Firefox  Record, execute, edit, debug tests in the  browser
  13. Show Me A Demo!
  14. End-to-End Testing Selenium RC Automated execution of Selenium tests  One test can be executed on multiple  OS / browser combinations Tests can be specified in any language  Bindings for PHP: Testing_Selenium  PHPUnit has its own implementation 
  15. End-to-End Testing Selenium RC
  16. End-to-End Testing Problems Complex test environments  Dependencies between tests  Isolation of test execution  Running the tests is slow,  thus incompatible with the agile approach
  17. End-to-End Testing Problems End-to-End Testing is not enough and/or does not scale We want to test earlier  We want to be able to test an  incomplete application We want a test environment that is  less complex We want to be able to run the tests faster 
  18. Does my code work?  Be confident in your code!  Do not be afraid of changing your code! 
  19. Does my code work? Classic Approach Write a test program  Run the test program  Manually verify the output  Delete the test program 
  20. Does my code work? Agile Approach Write a unit test Automatic evaluation of the test result  Instant feedback  Simple test environment  Allows for the earliest possible testing of a  code unit Executable specification  Is not deleted but kept as regression test 
  21. Unit Tests improve the confidence in your code as they detect problems as early as possible
  22. PHPUnit Website
  23. PHPUnit Installation sb@ubuntu ~ % pear channel-discover pear.phpunit.de Adding Channel \"pear.phpunit.de\" succeeded Discovery of channel \"pear.phpunit.de\" succeeded sb@ubuntu ~ % pear install phpunit/phpunit downloading PHPUnit-3.3.0.tgz ... Starting to download PHPUnit-3.3.0.tgz (264,345 bytes) ...................................done: 264,345 bytes install ok: channel://pear.phpunit.de/PHPUnit-3.3.0
  24. 10 frames  2 rolls to knock down the 10 pins  Score for a frame is the number of pins knocked down  Bonus for a spare (all 10 pins knocked down in two tries): next roll  Bonus for a strike (all 10 pins knocked down in one try): next two rolls  Extra rolls for spare or strike in the 10th frame 
  25. Show Me The Code!
  26. The Bowling Game Kata The first test <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { }
  27. The Bowling Game Kata The first test <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { public function testScoreForGutterGameIs0() { } }
  28. The Bowling Game Kata The first test <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { public function testScoreForGutterGameIs0() { $game = new BowlingGame; for ($i = 0; $i < 20; $i++) { $game->roll(0); } $this->assertEquals(0, $game->score()); } }
  29. The Bowling Game Kata Generating a class skeleton sb@ubuntu ~ % phpunit --skeleton-class BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. Wrote skeleton for \"BowlingGame\" to \"BowlingGame.php\". <?php class BowlingGame { /** * @todo Implement roll(). */ public function roll() { // Remove the following line when you implement this method. throw new RuntimeException('Not yet implemented.'); } /** * @todo Implement score(). */ public function score() { // Remove the following line when you implement this method. throw new RuntimeException('Not yet implemented.'); } } ?>
  30. The Bowling Game Kata Running the tests of a test case class sb@ubuntu ~ % phpunit BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. E Time: 0 seconds There was 1 error: 1) testScoreForGutterGameIs0(BowlingGameTest) RuntimeException: Not yet implemented. /home/sb/BowlingGame.php:10 /home/sb/BowlingGameTest.php:11 FAILURES! Tests: 1, Assertions: 0, Errors: 1.
  31. The Bowling Game Kata The BowlingGame class <?php class BowlingGame { public function roll($pins) { } public function score() { return 0; } }
  32. The Bowling Game Kata Running the tests of a test case class sb@ubuntu ~ % phpunit BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. . Time: 0 seconds OK (1 test, 1 assertion)
  33. The Bowling Game Kata Running the tests of a test case class sb@ubuntu ~ % phpunit --colors BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. . Time: 0 seconds 1 assertion) OK (1 test, 0 assertions)
  34. Test-Driven Development Method of designing software,  not just a method of testing software Tests drive the development  Tests written before code  No code without tests 
  35. Test-Driven Development Test  What do we want score() to do?  How do we want to tell score() to do it?  How will we know when score() has done it?  Code  How does score() do it? 
  36. The best time to test is when the code is fresh Your code is like clay. When it’s fresh, it’s soft and malleable. As it ages, it becomes hard and brittle. If you write tests when the code is fresh and easy to change, testing will be easy, and both the code and the tests will be strong. This slide contains material by Alberto Savoia
  37. Think of code and test as one When writing the code, think of the test. When writing the test, think of the code. When you think of code and test as one, testing is easy and code is beautiful. This slide contains material by Alberto Savoia
  38. The Bowling Game Kata The second test <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { // ... public function testScoreForAllOnesIs20() { $game = new BowlingGame; for ($i = 0; $i < 20; $i++) { $game->roll(1); } $this->assertEquals(20, $game->score()); } }
  39. The Bowling Game Kata The second test sb@ubuntu ~ % phpunit BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. .F Time: 0 seconds There was 1 failure: 1) testScoreForAllOnesIs20(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:20>. /home/sb/BowlingGameTest.php:25 FAILURES! Tests: 2, Assertions: 2, Failures: 1.
  40. The Bowling Game Kata The second test sb@ubuntu ~ % phpunit --colors BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. .F Time: 0 seconds There was 1 failure: 1) testScoreForAllOnesIs20(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:20>. /home/sb/BowlingGameTest.php:25 FAILURES! Tests: 1, Failures: 1.2, Failures: 1. 2, Assertions:
  41. The Bowling Game Kata Leveraging the setUp() method <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { protected $game; protected function setUp() { $this->game = new BowlingGame; } // ... public function testScoreForAllOnesIs20() { for ($i = 0; $i < 20; $i++) { $this->game->roll(1); } $this->assertEquals(20, $this->game->score()); } // ... }
  42. The Bowling Game Kata Introducing the rollMany() method <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { // ... protected function rollMany($n, $pins) { for ($i = 0; $i < $n; $i++) { $this->game->roll($pins); } } public function testScoreForGutterGameIs0() { $this->rollMany(20, 0); $this->assertEquals(0, $this->game->score()); } public function testScoreForAllOnesIs20() { $this->rollMany(20, 1); $this->assertEquals(20, $this->game->score()); } }
  43. The Bowling Game Kata The third test <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { // ... public function testScoreForOneSpareAnd3Is16() { $this->game->roll(5); $this->game->roll(5); $this->game->roll(3); $this->rollMany(17, 0); $this->assertEquals(16, $this->game->score()); } }
  44. The Bowling Game Kata The fourth test <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { // ... public function testScoreForOneStrikeAnd3And4Is24() { $this->game->roll(10); $this->game->roll(3); $this->game->roll(4); $this->rollMany(17, 0); $this->assertEquals(24, $this->game->score()); } }
  45. The Bowling Game Kata The fifth test <?php require_once 'BowlingGame.php'; class BowlingGameTest extends PHPUnit_Framework_TestCase { // ... public function testScoreForPerfectGameIs300() { $this->rollMany(12, 10); $this->assertEquals(300, $this->game->score()); } }
  46. The Bowling Game Kata sb@ubuntu ~ % phpunit BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. .FFFF Time: 0 seconds There were 4 failures: 1) testScoreForAllOnesIs20(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:20>. /home/sb/BowlingGameTest.php:67 2) testScoreForOneSpareAnd3Is16(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:16>. /home/sb/BowlingGameTest.php:75 3) testScoreForOneStrikeAnd3And4Is24(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:24>. /home/sb/BowlingGameTest.php:84 4) testScoreForPerfectGameIs300(BowlingGameTest) Failed asserting that <integer:0> matches expected value <integer:300>. /home/sb/BowlingGameTest.php:90 FAILURES! Tests: 5, Assertions: 5, Failures: 4.
  47. The Bowling Game Kata TestDox: Tests as executable specification sb@ubuntu ~ % phpunit --testdox BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. BowlingGame [x] Score for gutter game is 0 [ ] Score for all ones is 20 [ ] Score for one spare and 3 is 16 [ ] Score for one strike and 3 and 4 is 24 [ ] Score for perfect game is 300
  48. The Bowling Game Kata The BowlingGame class <?php class BowlingGame { protected $rolls = array(); public function roll($pins) { $this->rolls[] = $pins; } // ... }
  49. The Bowling Game Kata The BowlingGame class <?php class BowlingGame { // ... protected function isSpare($frameIndex) { return $this->sumOfPinsInFrame($frameIndex) == 10; } protected function isStrike($frameIndex) { return $this->rolls[$frameIndex] == 10; } protected function sumOfPinsInFrame($frameIndex) { return $this->rolls[$frameIndex] + $this->rolls[$frameIndex + 1]; } }
  50. The Bowling Game Kata The BowlingGame class <?php class BowlingGame { // ... protected function spareBonus($frameIndex) { return $this->rolls[$frameIndex + 2]; } protected function strikeBonus($frameIndex) { return $this->rolls[$frameIndex + 1] + $this->rolls[$frameIndex + 2]; } }
  51. The Bowling Game Kata The BowlingGame class <?php class BowlingGame { // ... public function score() { $score = 0; $frameIndex = 0; for ($frame = 0; $frame < 10; $frame++) { if ($this->isStrike($frameIndex)) { $score += 10 + $this->strikeBonus($frameIndex); $frameIndex++; } else if ($this->isSpare($frameIndex)) { $score += 10 + $this->spareBonus($frameIndex); $frameIndex += 2; } else { $score += $this->sumOfPinsInFrame($frameIndex); $frameIndex += 2; } } return $score; } }
  52. The Bowling Game Kata TestDox: Tests as executable specification sb@ubuntu ~ % phpunit --testdox BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. BowlingGame [x] Score for gutter game is 0 [x] Score for all ones is 20 [x] Score for one spare and 3 is 16 [x] Score for one strike and 3 and 4 is 24 [x] Score for perfect game is 300
  53. The Bowling Game Kata Generating a test skeleton sb@ubuntu ~ % phpunit --skeleton-test BowlingGame PHPUnit 3.4.0 by Sebastian Bergmann. Wrote skeleton for \"BowlingGameTest\" to \"BowlingGameTest.php\". sb@ubuntu ~ % phpunit --verbose BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. BowlingGameTest II Time: 0 seconds There were 2 incomplete tests: 1) testRoll(BowlingGameTest) This test has not been implemented yet. /home/sb/BowlingGameTest.php:46 2) testScore(BowlingGameTest) This test has not been implemented yet. /home/sb/BowlingGameTest.php:56 OK, but incomplete or skipped tests! Tests: 2, Assertions: 0, Incomplete: 2.
  54. The Bowling Game Kata Code Coverage sb@ubuntu ~ % phpunit --coverage-html /tmp/report BowlingGameTest PHPUnit 3.4.0 by Sebastian Bergmann. ..... Time: 0 seconds OK (5 tests, 5 assertions) Generating report, this may take a moment.
  55. Show Me A Demo!
  56. Test Doubles How can we verify logic independently  when code it depends on is unusable? How can we avoid slow tests?  We replace a component on which the SUT  depends with a “test-specific equivalent”.
  57. Test Doubles Terminology Dummy  Not the real object Fake  Usable for testing but not for real job Stub  Fake that returns canned data Spy  Stub that records called methods, etc. Mock  Spy with expectations
  58. PHPUnit Stubs <?php require_once 'PHPUnit/Framework.php'; class StubTest extends PHPUnit_Framework_TestCase { public function testStub() { } } ?>
  59. PHPUnit Stubs <?php require_once 'PHPUnit/Framework.php'; class StubTest extends PHPUnit_Framework_TestCase { public function testStub() { $stub = $this->getMock('SomeClass'); } } ?>
  60. PHPUnit Stubs: returnValue() <?php require_once 'PHPUnit/Framework.php'; class StubTest extends PHPUnit_Framework_TestCase { public function testStub() { $stub = $this->getMock('SomeClass'); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnValue('foo')); } } ?>
  61. PHPUnit Stubs: returnValue() <?php require_once 'PHPUnit/Framework.php'; class StubTest extends PHPUnit_Framework_TestCase { public function testStub() { $stub = $this->getMock('SomeClass'); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnValue('foo')); // Calling $stub->doSomething() will now return // 'foo'. } } ?>
  62. PHPUnit Stubs: returnArgument() <?php class StubTest extends PHPUnit_Framework_TestCase { public function testReturnArgumentStub() { $stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnArgument(0)); // $stub->doSomething('foo') returns 'foo' // $stub->doSomething('bar') returns 'bar' } }
  63. PHPUnit Stubs: returnCallback() <?php class StubTest extends PHPUnit_Framework_TestCase { public function testReturnCallbackStub() { $stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->returnCallback('callback')); // $stub->doSomething() returns callback(...) } } function callback() { $args = func_get_args(); // ... }
  64. PHPUnit Stubs: throwException() <?php class StubTest extends PHPUnit_Framework_TestCase { public function testThrowExceptionStub() { $stub = $this->getMock( 'SomeClass', array('doSomething') ); $stub->expects($this->any()) ->method('doSomething') ->will($this->throwException(new Exception)); // $stub->doSomething() throws Exception } }
  65. PHPUnit Mocks <?php require_once 'PHPUnit/Framework.php'; class ObserverTest extends PHPUnit_Framework_TestCase { public function testUpdateIsCalledOnce() { } } ?>
  66. PHPUnit Mocks <?php require_once 'PHPUnit/Framework.php'; class ObserverTest extends PHPUnit_Framework_TestCase { public function testUpdateIsCalledOnce() { $observer = $this->getMock( 'Observer', array('update') ); } } ?>
  67. PHPUnit Mocks <?php require_once 'PHPUnit/Framework.php'; class ObserverTest extends PHPUnit_Framework_TestCase { public function testUpdateIsCalledOnce() { $observer = $this->getMock( 'Observer', array('update') ); $observer->expects($this->once()) ->method('update') ->with($this->equalTo('something')); } } ?>
  68. PHPUnit Mocks <?php require_once 'PHPUnit/Framework.php'; class ObserverTest extends PHPUnit_Framework_TestCase { public function testUpdateIsCalledOnce() { $observer = $this->getMock( 'Observer', array('update') ); $observer->expects($this->once()) ->method('update') ->with($this->equalTo('something')); $subject = new Subject; $subject->attach($observer); $subject->doSomething(); } } ?>
  69. PHPUnit Data Provider <?php class DataTest extends PHPUnit_Framework_TestCase { /** * @dataProvider providerMethod */ public function testAdd($a, $b, $c) { $this->assertEquals($c, $a + $b); } public function providerMethod() { return array( array(0, 0, 0), array(0, 1, 1), array(1, 1, 3), array(1, 0, 1) ); } }
  70. PHPUnit Data Provider sb@ubuntu ~ % phpunit DataTest PHPUnit 3.3.0 by Sebastian Bergmann. ..F. Time: 0 seconds There was 1 failure: 1) testAdd(DataTest) with data (1, 1, 3) Failed asserting that <integer:2> matches expected value <integer:3>. /home/sb/DataTest.php:19 FAILURES! Tests: 4, Assertions: 4, Failures: 1.
  71. PHPUnit DatabaseTestCase Used to test database-driven projects Puts the database into a known state  between test runs Avoids problems with one test corrupting the  database for other tests Ability to export and import data to and from  XML and YAML datasets
  72. PHPUnit DatabaseTestCase Uses PDO to connect to the  database-under-test Tested application does not have to use  PDO itself
  73. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { }
  74. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { protected $pdo; public function __construct() { $this->pdo = PHPUnit_Util_PDO::factory( 'mysql://test@localhost/test' ); BankAccount::createTable($this->pdo); } }
  75. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { protected $pdo; public function __construct() { $this->pdo = PHPUnit_Util_PDO::factory( 'mysql://test@localhost/test' ); BankAccount::createTable($this->pdo); } protected function getConnection() { return $this->createDefaultDBConnection($this->pdo, 'mysql'); } }
  76. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { protected $pdo; public function __construct() { $this->pdo = PHPUnit_Util_PDO::factory( 'mysql://test@localhost/test' ); BankAccount::createTable($this->pdo); } protected function getConnection() { return $this->createDefaultDBConnection($this->pdo, 'mysql'); } protected function getDataSet() { return $this->createFlatXMLDataSet('/path/to/seed.xml'); } }
  77. PHPUnit DatabaseTestCase <dataset> <account account_number=\"15934903649620486\" balance=\"100.00\" /> <account account_number=\"15936487230215067\" balance=\"1216.00\" /> <account account_number=\"12348612357236185\" balance=\"89.00\" /> <account account_number=\"15936487230215067\" balance=\"1216.00\" /> </dataset>
  78. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { // ... public function testNewAccount() { } }
  79. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { // ... public function testNewAccount() { $ba = new BankAccountDB('12345678912345678', $this->pdo); } }
  80. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { // ... public function testNewAccount() { $ba = new BankAccountDB('12345678912345678', $this->pdo); $set = $this->createFlatXMLDataSet( '/path/to/after-new-account.xml' ); } }
  81. PHPUnit DatabaseTestCase <?php require_once 'PHPUnit/Extensions/Database/TestCase.php'; class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase { // ... public function testNewAccount() { $ba = new BankAccountDB('12345678912345678', $this->pdo); $set = $this->createFlatXMLDataSet( '/path/to/after-new-account.xml' ); $this->assertTablesEqual( $set->getTable('account'), $this->getConnection() ->createDataSet() ->getTable('account') ); } }
  82. PHPUnit DatabaseTestCase <dataset> <account account_number=\"15934903649620486\" balance=\"100.00\" /> <account account_number=\"15936487230215067\" balance=\"1216.00\" /> <account account_number=\"12348612357236185\" balance=\"89.00\" /> <account account_number=\"15936487230215067\" balance=\"1216.00\" /> <account account_number=\"12345678912345678\" balance=\"0.00\" /> </dataset>
  83. PHPUnit If possible, test against SQLite When testing PHP code that uses PDO to connect to a database, it makes sense to keep your SQL compatible with SQLite No server ⇒ No inter-process communication  In-Memory Databases ⇒ No Disk I/O  User System CPU Total 3.95s 0.87s 40% 12.046s PDO / MySQL 5.01s 1.54s 63% 10.359s PDO / SQLite (file) PDO / SQLite (memory) 3.16s 0.68s 99% 3.849s
  84. PHPUnit Integration with Selenium RC <?php require_once 'PHPUnit/Extensions/SeleniumTestCase.php'; class WebTest extends PHPUnit_Extensions_SeleniumTestCase { } ?>
  85. PHPUnit Integration with Selenium RC <?php require_once 'PHPUnit/Extensions/SeleniumTestCase.php'; class WebTest extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { $this->setBrowser('*firefox'); $this->setBrowserUrl('http://www.example.com/'); $this->setSleep(10); } } ?>
  86. PHPUnit Integration with Selenium RC <?php require_once 'PHPUnit/Extensions/SeleniumTestCase.php'; class WebTest extends PHPUnit_Extensions_SeleniumTestCase { protected function setUp() { $this->setBrowser('*firefox'); $this->setBrowserUrl('http://www.example.com/'); $this->setSleep(10); } public function testTitle() { $this->open('http://www.example.com/'); $this->assertTitle('Example Web Page'); } } ?>
  87. Show Me A Demo!
  88. How do we measure Software Quality?
  89. Software Metrics A software metric is a measure of some  property of a piece of software or its specifications. „You cannot control what you cannot  measure.“ (Tom DeMarco)
  90. Software Metrics Code Coverage Which statements, branches, and paths  are executed when the tests run? C0-Coverage: Statement Coverage  C1-Coverage: Branch Coverage  C-Coverage: Path Coverage  100% Code Coverage is a required, but  not a sufficient criteria for test completeness
  91. Software Metrics Lines of Code Text-based metric for code size  Various definitions  Lines of Code (LOC)  Comment Lines of Code (CLOC)  Non-Comment Lines of Code (NCLOC)  Executable Lines of Code (ELOC)  Ratios can be interesting  CLOC / (E)LOC 
  92. Software Metrics Lines of Code sb@ubuntu ~ % pear install phpunit/phploc downloading phploc-1.0.0.tgz ... Starting to download phploc-1.0.0.tgz (5,834 bytes) .....done: 5,834 bytes install ok: channel://pear.phpunit.de/phploc-1.0.0 sb@ubuntu ~ % phploc /usr/local/src/ezcomponents/trunk/Workflow phploc 1.0.0 by Sebastian Bergmann. Directories: 13 Files: 102 Lines of Code (LOC): 14066 Executable Lines of Code (ELOC): 5710 Comment Lines of Code (CLOC): 5228 Non-Comment Lines of Code (NCLOC): 8838 Interfaces: 7 Classes: 90 Functions/Methods: 566
  93. Software Metrics Code Duplication Two sequences of code are duplicate  when they are textually identical  token for token identical  functionally identical  Problems  Duplicate code contradicts code reuse  Co-Evolution of clones hinders maintenance 
  94. Software Metrics Code Duplication sb@ubuntu ~ % pear install phpunit/phpcpd downloading phpcpd-1.1.0.tgz ... Starting to download phpcpd-1.1.0.tgz (8,226 bytes) .....done: 8,226 bytes install ok: channel://pear.phpunit.de/phpcpd-1.1.0 sb@ubuntu ~ % phpcpd /usr/local/src/phpunit/trunk/PHPUnit phpcpd 1.1.0 by Sebastian Bergmann. Found 4 exact clones with 131 duplicated lines in 7 files: - Extensions/Database/DataSet/AbstractTable.php:156-190 Extensions/Database/DataSet/ReplacementTable.php:172-206 - Samples/BankAccountDB/BankAccountDBTest.php:84-128 Samples/BankAccountDB/BankAccountDBTestMySQL.php:84-128 - Tests/Extensions/Database/DataSet/XmlDataSetsTest.php:71-98 Tests/Extensions/Database/DataSet/YamlDataSetTest.php:70-97 - Tests/Extensions/Database/DataSet/XmlDataSetsTest.php:71-97 Tests/Extensions/Database/DataSet/CsvDataSetTest.php:70-96 0.21% duplicated lines out of 61720 total lines of code.
  95. Software Metrics Cyclomatic Complexity Measures the complexity of a code unit  Originally defined in graph theory  ccn(G) = Edges - Vertices + 2 Equivalent: Counting the branching points  if, for, foreach, while, case, catch, &&, ||, ternary operator (?:) Interpretation  Higher complexity leads to more errors  Higher complexity makes testing harder 
  96. Software Metrics Cyclomatic Complexity <?php function isLeapYear($year) 1 { $result = false; if ($year % 4 != 0) { 2 $result = false; } 3 if ($year % 100 != 0) { $result = true; } 4 if ($year % 400 == 0) { $result = true; } return $result; }
  97. Software Metrics pdepend Static Analysis of PHP Code  Software Metrics  Software Visualization  Helps to identify parts of an application  that should be refactored sb@ubuntu ~ % pear channel-discover pear.pdepend.org Adding Channel \"pear.pdepend.org\" succeeded Discovery of channel \"pear.pdepend.org\" succeeded sb@ubuntu ~ % pear install pdepend/PHP_Depend downloading PHP_Depend-0.9.4.tgz ... Starting to download PHP_Depend-0.9.4.tgz (161,553 bytes) ..................................done: 161,553 bytes install ok: channel://pear.pdepend.org/PHP_Depend-0.9.4
  98. Show Me A Demo!
  99. Software Metrics phpmd Static Analysis of PHP Code  Based on PHP_Depend  Reports violations of rules that operate on  raw software metrics data
  100. Software Metrics phpcs Static Analysis of PHP Code  Based on ext/tokenizer  ”Sniffs”  Coding Standard  Software Metrics  Bug Patterns  Performance Patterns  ... 
  101. QA Tools for PHP phpunit → JUnit XML and Clover XML  phpcs → Checkstyle XML  pdepend → JDepend XML  phpmd → PMD XML  phpcpd → PMD-CPD XML 
  102. Build Automation Apache Ant Java-based build tool  Kind of like make, without make's  wrinkles Build files are XML-based, calling out a  target tree where various tasks get executed
  103. Build Automation Apache Ant <project name=\"Money\" default=\"build\"> <target name=\"clean\"> <delete dir=\"${basedir}/build\"/> </target> <target name=\"prepare\"> <mkdir dir=\"${basedir}/build/logs\"/> </target> <target name=\"phpcs\"> <exec dir=\"${basedir}\" executable=\"phpcs\" output=\"${basedir}/build/logs/checkstyle.xml\" failonerror=\"false\"> <arg line=\"--report=checkstyle .\"/> </exec> </target> <target name=\"phpmd\"> <exec dir=\"${basedir}\" executable=\"phpmd\" failonerror=\"false\"> <arg line=\". xml codesize --reportfile ${basedir}/build/logs/pmd.xml\"/> </exec> </target>
  104. Build Automation Apache Ant <target name=\"phpcpd\"> <exec dir=\"${basedir}\" executable=\"phpcpd\" failonerror=\"false\"> <arg line=\"--log-pmd=${basedir}/build/logs/pmd-cpd.xml .\"/> </exec> </target> <target name=\"pdepend\"> <exec dir=\"${basedir}\" executable=\"pdepend\" failonerror=\"false\"> <arg line=\"--jdepend-xml=${basedir}/build/logs/jdepend.xml .\"/> </exec> </target> <target name=\"phpunit\"> <exec dir=\"${basedir}\" executable=\"phpunit\" failonerror=\"true\"> <arg line=\"--log-xml ${basedir}/build/logs/junit.xml --coverage-clover ${basedir}/build/logs/clover.xml MoneyTest\"/> </exec> </target> <target name=\"build\" depends=\"clean,prepare,phpcs,phpmd,phpcpd,pdepend,phpunit\"/> </project>
  105. Build Automation Apache Ant sb@ubuntu Money % ant Buildfile: build.xml clean: [delete] Deleting directory /home/sb/Money/build prepare: [mkdir] Created dir: /home/sb/Money/build/logs phpcs: phpmd: phpcpd: [exec] phpcpd 1.1.0 by Sebastian Bergmann. [exec] [exec] 0.00% duplicated lines out of 722 total lines of code. pdepend: [exec] PHP_Depend 0.9.4 by Manuel Pichler [exec] [exec] Executing Dependency-Analyzer: [exec] 16 [exec] [exec] Generating pdepend log files, this may take a moment. phpunit: [exec] PHPUnit 3.4.0 by Sebastian Bergmann. [exec] [exec] ...................... [exec] [exec] Time: 0 seconds [exec] [exec] OK (22 tests, 34 assertions) [exec] [exec] Writing code coverage data to XML file, this may take a moment. build: BUILD SUCCESSFUL Total time: 4 seconds
  106. Continuous Integration Software development practice where  members of a team integrate their work frequently Usually each person integrates at least daily,  leading to multiple integrations per day Each integration is verified by an  automated build (including test) to detect integration errors as quickly as possible Leads to significantly reduced integration  problems and allows a team to develop cohesive software more rapidly
  107. Continuous Integration CruiseControl Framework for a continuous build process Includes, but is not limited to, plugins for  email notification, Apache Ant, Phing, and various source control tools A web interface is provided to view the  details of the current and previous builds
  108. Continuous Integration phpUnderControl Customization of CruiseControl that caters to the needs of PHP projects PHPUnit  PHPDocumentor  PHP_CodeSniffer  (PHP_Depend)  (phpmd)  (phpcpd) 
  109. Show Me A Demo!
  110. The End Thank you for your interest! These slides will be posted on http://www.slideshare.net/sebastian_bergmann You can vote for this talk on http://joind.in/321
  111. License This presentation material is published under the Attribution-Share Alike 3.0 Unported   license. You are free:   to Share – to copy, distribute and transmit the work. ✔ to Remix – to adapt the work. ✔ Under the following conditions:   Attribution. You must attribute the work in the manner specified by the author or ● licensor (but not in any way that suggests that they endorse you or your use of the work). Share Alike. If you alter, transform, or build upon this work, you may distribute the ● resulting work only under the same, similar or a compatible license. For any reuse or distribution, you must make clear to others the license terms of this   work. Any of the above conditions can be waived if you get permission from the copyright   holder. Nothing in this license impairs or restricts the author's moral rights.  

+ Sebastian BergmannSebastian Bergmann, 10 months ago

custom

4030 views, 13 favs, 19 embeds more stats

More info about this presentation

CC Attribution-ShareAlike LicenseCC Attribution-ShareAlike License

  • Total Views 4030
    • 3382 on SlideShare
    • 648 from embeds
  • Comments 1
  • Favorites 13
  • Downloads 186
Most viewed embeds
  • 536 views on http://sebastian-bergmann.de
  • 44 views on http://www.planet-php.net
  • 19 views on http://www.nqbao.com
  • 14 views on http://bao.nguyenquoc.com
  • 9 views on http://www.bookreactor.com

more

All embeds
  • 536 views on http://sebastian-bergmann.de
  • 44 views on http://www.planet-php.net
  • 19 views on http://www.nqbao.com
  • 14 views on http://bao.nguyenquoc.com
  • 9 views on http://www.bookreactor.com
  • 5 views on http://planet-php.org
  • 4 views on http://static.slideshare.net
  • 3 views on http://www.planet-php.org
  • 3 views on http://www.phpconsultant.in
  • 2 views on http://www.brijj.com
  • 1 views on http://sotayblog.com
  • 1 views on http://www.mefeedia.com
  • 1 views on http://localhost
  • 1 views on http://66.249.89.132
  • 1 views on http://planet-php.net
  • 1 views on http://lj-toys.com
  • 1 views on http://rss.mmckeon.com
  • 1 views on http://xss.yandex.net
  • 1 views on http://translate.googleusercontent.com

less

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

Cancel
File a copyright complaint
Having problems? Go to our helpdesk?

Categories

Groups / Events