UNITTESTING IN SILVERSTRIPE
A couple of tricks you might not know about
Ingo Schommer (@chillu), October 2010
Wednesday, 1...
MORE EXPRESSIVE ASSERTIONS
Bad: Generic assertion, little debugging value
<?php
class MyFileCreatorTest extends Functional...
MORE EXPRESSIVE ASSERTIONS
Good: Use assertions that communicate failures better
<?php
class MyFileCreatorTest extends Fun...
MORE EXPRESSIVE ASSERTIONS
Useful built-in assertions:
assertType(<string>, <object>)
assertArrayHasKey(<key>, <array>)
as...
MORE EXPRESSIVE ASSERTIONS
$members = DataObject::get('Member');
$this->assertContains('test@test.com',$members->column('E...
PHPUNIT EXECUTABLE INSTEAD OF SAKE
New feature since 2.4.3, backported to 2.3.9 as well
More features than proxying throug...
PHPUNIT EXECUTABLE INSTEAD OF SAKE
With “sake”
phpunit .
phpunit sapphire
phpunit sapphire/tests/DataObjectTest.php
phpuni...
PHPUNIT: RUN ALLTESTS IN A FOLDER
phpunit --verbose sapphire/tests/security
PHPUnit 3.5.3 by Sebastian Bergmann.
sapphire/...
PHPUNIT: RUN ONLY ONETEST METHOD
Less hacky than commenting out other tests
Supports regular expressions
phpunit --filter ...
FASTERTESTSTHROUGH SQLITE3
Up to 10x faster test execution¹ means
“Test Driven Development” (TDD) is fun again!Thanks Andr...
FASTERTESTSTHROUGH SQLITE3
Needs the sqlite3 module in your project
http://silverstripe.org/sqlite-database/
Simple modific...
DEBUGGING A FIXTURE
YAML fixtures are more concise than SQL inserts
Problem: You have to run queries and joins in your head...
DEBUGGING A FIXTURE
For more complex data models, looking at SQL can be easier
SilverStripe lets you load aYAML fixture int...
SEPARATE INTEGRATION AND UNITTESTS
A UnitTest (SapphireTest class) covers an isolated aspect of a class,
e.g. one method c...
SEPARATE INTEGRATION AND UNITTESTS
Unit and IntegrationTests complement each other,
both are necessary and have different ...
WRITE QUALITYTESTS
Lack of test coverage points to problems,
but high coverage doesn’t automatically mean quality code
cla...
WRITE QUALITYTESTS
High code coverage is the side effect of writing quality tests,
not a goal in itself.
Recommendation:
S...
WRITE FLEXIBLE INTEGRATIONTESTS
<div class="sidebar">
<ul>
<li class="news-item">
<a href="mylink">My first news</a>
</li>...
WRITE FLEXIBLE INTEGRATIONTESTS
Learn XPath (or use a CSS to XPath converter)
Learn SimpleXML (built-in with PHP5)
Make fe...
LINKS
Unit testing in SilverStripe
http://doc.silverstripe.org/testing-guide
Usage of “phpunit” executable in SilverStripe...
Upcoming SlideShare
Loading in...5
×

Unit Testing in SilverStripe

1,358

Published on

A couple of tricks you might not know about. Held at an internal developer show'n'tell in October 2010 at SilverStripe Ltd. in Wellington, New Zealand. Video available at http://vimeo.com/16446690

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,358
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
13
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Unit Testing in SilverStripe

  1. 1. UNITTESTING IN SILVERSTRIPE A couple of tricks you might not know about Ingo Schommer (@chillu), October 2010 Wednesday, 17 November 2010
  2. 2. MORE EXPRESSIVE ASSERTIONS Bad: Generic assertion, little debugging value <?php class MyFileCreatorTest extends FunctionalTest { function testFileGeneration() { $obj = new MyFileCreator(); $filepath = $obj->createFile(); $this->assertEquals(file_exists($filepath), true); } } 1) MyFileCreatorTest::testFileGeneration Failed asserting that <boolean:true> matches expected <boolean:false>. Wednesday, 17 November 2010
  3. 3. MORE EXPRESSIVE ASSERTIONS Good: Use assertions that communicate failures better <?php class MyFileCreatorTest extends FunctionalTest { function testFileGeneration() { $obj = new MyFileCreator(); $filepath = $obj->createFile(); $this->assertFileExists($filepath); } } 1) MyFileCreatorTest::testFileGeneration Failed asserting that file "/my/path/file.txt" exists. Wednesday, 17 November 2010
  4. 4. MORE EXPRESSIVE ASSERTIONS Useful built-in assertions: assertType(<string>, <object>) assertArrayHasKey(<key>, <array>) assertContains(<needle>, <haystack>) assertEmailSent($to, $from = null, $subject = null, $content = null) assertDOSContains($matches, $dataObjectSet) Useful custom assertions in SapphireTest: Wednesday, 17 November 2010
  5. 5. MORE EXPRESSIVE ASSERTIONS $members = DataObject::get('Member'); $this->assertContains('test@test.com',$members->column('Email')); $member = DataObject::get_one('Member', '"Email" = 'test@test.com''); $this->assertType('Member', $member); Using assertType() Using DataObjectSet->column() Wednesday, 17 November 2010
  6. 6. PHPUNIT EXECUTABLE INSTEAD OF SAKE New feature since 2.4.3, backported to 2.3.9 as well More features than proxying through “sake” CLI tool Code coverage generation in “XML Clover” format (which can be parsed by phpUnderControl and other tools) Wednesday, 17 November 2010
  7. 7. PHPUNIT EXECUTABLE INSTEAD OF SAKE With “sake” phpunit . phpunit sapphire phpunit sapphire/tests/DataObjectTest.php phpunit --coverage-html assets/ sake dev/tests/all sake dev/tests/modules/sapphire sake dev/tests/DataObjectTest sake dev/tests/coverage With “phpunit” Wednesday, 17 November 2010
  8. 8. PHPUNIT: RUN ALLTESTS IN A FOLDER phpunit --verbose sapphire/tests/security PHPUnit 3.5.3 by Sebastian Bergmann. sapphire/tests/security BasicAuthTest .... GroupTest ... Time: 9 seconds, Memory: 83.50Mb OK (72 tests, 286 assertions) More granular control over which tests are run Filepath autocompletion built-in on CLI Wednesday, 17 November 2010
  9. 9. PHPUNIT: RUN ONLY ONETEST METHOD Less hacky than commenting out other tests Supports regular expressions phpunit --filter testDelete sapphire/tests/DataObjectTest.php PHPUnit 3.5.3 by Sebastian Bergmann. . Time: 1 second, Memory: 64.75Mb Wednesday, 17 November 2010
  10. 10. FASTERTESTSTHROUGH SQLITE3 Up to 10x faster test execution¹ means “Test Driven Development” (TDD) is fun again!Thanks Andreas :) phpunit mysite/tests '' db=sqlite3 ... Time: 2:44 seconds, Memory: 113.75Mb phpunit mysite/tests ... Time: 22:56, Memory: 116.75Mb PostgreSQL Sqlite3 ¹ Internal project on SilverStripe 2.4.2, with 97 tests and 410 assertions. Postgresql and SQLite3 modules both on trunk. Wednesday, 17 November 2010
  11. 11. FASTERTESTSTHROUGH SQLITE3 Needs the sqlite3 module in your project http://silverstripe.org/sqlite-database/ Simple modification in mysite/_config.php require_once('conf/ConfigureFromEnv.php'); // ... if(Director::isDev() && @$_REQUEST['db'] == 'sqlite3') { $databaseConfig['type'] = 'SQLite3Database'; } Not a complete replacement to running tests on the actual database driver, but most of the time implementations are the same. Wednesday, 17 November 2010
  12. 12. DEBUGGING A FIXTURE YAML fixtures are more concise than SQL inserts Problem: You have to run queries and joins in your head Wednesday, 17 November 2010
  13. 13. DEBUGGING A FIXTURE For more complex data models, looking at SQL can be easier SilverStripe lets you load aYAML fixture into a temporary database through http://localhost/dev/tests/startsession Wednesday, 17 November 2010
  14. 14. SEPARATE INTEGRATION AND UNITTESTS A UnitTest (SapphireTest class) covers an isolated aspect of a class, e.g. one method call. An IntegrationTest (FunctionalTest class) tests the sum of its parts, in SilverStripe mostly HTTP requests and their HTML responses. Wednesday, 17 November 2010
  15. 15. SEPARATE INTEGRATION AND UNITTESTS Unit and IntegrationTests complement each other, both are necessary and have different intentions. Good practice: Separate tests into different folders. Example: mysite/tests/unit and mysite/tests/integration Idea: Run coverage reports separately for unit and integration tests Wednesday, 17 November 2010
  16. 16. WRITE QUALITYTESTS Lack of test coverage points to problems, but high coverage doesn’t automatically mean quality code class HomepageTest extends FunctionalTest { function testResponse() { $response = $this->get('home'); $this->assertNotNull($response->getBody()); $this->assertEquals($response->getStatusCode(200)); } } Probably gives you 80% code coverage for a Homepage class, but failures don’t tell you anything useful. Bad example: Wednesday, 17 November 2010
  17. 17. WRITE QUALITYTESTS High code coverage is the side effect of writing quality tests, not a goal in itself. Recommendation: Strive for high unit test coverage, and highlevel “smoke tests” through integration tests Wednesday, 17 November 2010
  18. 18. WRITE FLEXIBLE INTEGRATIONTESTS <div class="sidebar"> <ul> <li class="news-item"> <a href="mylink">My first news</a> </li> <!-- ... --> </ul> </div> class HomepageTest extends FunctionalTest { function testSidebarShowsLatestNews() { $response = $this->get('home'); $newsEls = $response->cssParser()->getBySelector('.sidebar .news-item'); $this->assertEquals(3, count($newsEls), 'Shows three items'); $news1LinkEls = $newsEls[0]->xpath('.//a'); // relative xpath $this->assertEquals( 'My first news', (string)$news1LinkEls[0], 'News item link contains correct title' ); } } Wednesday, 17 November 2010
  19. 19. WRITE FLEXIBLE INTEGRATIONTESTS Learn XPath (or use a CSS to XPath converter) Learn SimpleXML (built-in with PHP5) Make few assumptions about template markup Make assertions less brittle by using semantic markup Wednesday, 17 November 2010
  20. 20. LINKS Unit testing in SilverStripe http://doc.silverstripe.org/testing-guide Usage of “phpunit” executable in SilverStripe http://goo.gl/D23KJ Book:“Test Driven Development: By Example” (Kent Beck) Wednesday, 17 November 2010
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×