31
Test in Action – Week 2 Testing Framework Hubert Chan

Test in action week 2

Embed Size (px)

Citation preview

Page 1: Test in action   week 2

Test in Action – Week 2Testing Framework

Hubert Chan

Page 2: Test in action   week 2

Testing Framework

• Why using framework?– Reinventing the wheel?– Frameworks provides• Library / API / Syntactic Sugar• xUnit Pattern• Stub / Mock• Log / Test Coverage• Static Analysis

Page 3: Test in action   week 2

PHPUnit

• PHPUnit– Unit Testing Framework– Most common for PHP– Open Source– Used in known PHP Frameworks• Zend Framework• Kohana• symfony

Page 4: Test in action   week 2

PHPUnit Installation

• Using pear– pear channel discover (only once)

pear channel-discover pear.phpunit.depear channel-discover components.ez.nopear channel-discover pear.symfony-project.com

– Install PHPUnitpear install phpunit/PHPUnit

Page 5: Test in action   week 2

PHPUnit Example

class StackTest extends PHPUnit_Framework_TestCase { public function testPushAndPop() { $stack = array(); $this->assertEquals(0, count($stack));

array_push($stack, 'foo'); $this->assertEquals('foo', $stack[count($stack)-1]); $this->assertEquals(1, count($stack));

$this->assertEquals('foo', array_pop($stack)); $this->assertEquals(0, count($stack)); }}

• Test Code

Page 6: Test in action   week 2

PHPUnit Test Cases Rule

• General Rule1. The tests for a class Class go into a class ClassTest.2. ClassTest inherits (most of the time) from

PHPUnit_Framework_TestCase.3. The tests are public methods that are named test*.4. Write Assertions

Page 7: Test in action   week 2

Data Provider

• Data Provider– Return an iterative object (Iterator interface)– Use for data-driven testing• Like ACM Input data

– Use it carefully

Page 8: Test in action   week 2

Data Provider Sample

class DataTest extends PHPUnit_Framework_TestCase { /** * @dataProvider provider */ public function testAdd($a, $b, $c) { $this->assertEquals($c, $a + $b); }

public function provider() { return array( array(0, 0, 0), array(0, 1, 1), array(1, 0, 1), array(1, 1, 3) ); }}

• Test Code

Page 9: Test in action   week 2

Testing Exception

• Testing Exception– Testing for failure cases– Error Handling– Examine• Exception Type• Exception Message• Exception Code

Page 10: Test in action   week 2

Testing Exception Sample

class ExceptionTest extends PHPUnit_Framework_TestCase { /** * @expectedException InvalidArgumentException * @expectedExceptionMessage Right Message */ public function testExceptionHasRightMessage() { throw new InvalidArgumentException('Some Message', 10); }

/** * @expectedException InvalidArgumentException * @expectedExceptionCode 20 */ public function testExceptionHasRightCode() { throw new InvalidArgumentException('Some Message', 10); }}

• Test Code

Page 11: Test in action   week 2

Testing Exception Sample

class ExceptionTest extends PHPUnit_Framework_TestCase {

public function testExceptionHasRightMessage() { $this->setExpectedException( 'InvalidArgumentException', 'Right Message' ); throw new InvalidArgumentException('Some Message', 10); }

public function testExceptionHasRightCode() { $this->setExpectedException( 'InvalidArgumentException', 'Right Message', 20 ); throw new InvalidArgumentException( 'The Right Message', 10 ); }}

• Test Code

Page 12: Test in action   week 2

Assertion

• Assertions– assertEquals– assertTrue / assertFalse– assertContains– and etc.

Page 13: Test in action   week 2

Assertion Guideline

• Assertion Guideline– Using best suitable assertion– Some assertions are more easy to use• assertXmlFileEqualsXmlFile()• assertRegExp()• and etc.

– Make assertion contains useful message

Page 14: Test in action   week 2

Assertion Compare - Equals

• Test Codeclass EqualTest extends PHPUnit_Framework_TestCase {

public function test_AssertTrue() { $this->assertTrue("123" === "456"); }

public function test_AssertEquals() { $this->assertEquals("123", "456"); }}

Page 15: Test in action   week 2

Assertion Compare – Equals (cont.)

• Output• Output1) EqualTest::test_AssertTrueFailed asserting that <boolean:false> is true.

/usr/home/hubert/tmp/php/equal_compare.php:6

2) EqualTest::test_AssertEqualsFailed asserting that two strings are equal.--- Expected+++ Actual@@ @@-123+456

/usr/home/hubert/tmp/php/equal_compare.php:10

Page 16: Test in action   week 2

Assertion Message

• Test Codeclass EqualTest extends PHPUnit_Framework_TestCase { public function test_AssertMessage() { $handler = new LogViewHandler(); $this->assertNotEmpty( $handler->generate_ajax(), "generate_ajax() should not be empty!!" ); }}

assertEmpty(mixed $actual[, string $message = ''])

• Prototype

Page 17: Test in action   week 2

Assertion Message - Output

• Output1) EqualTest::test_AssertMessagegenerate_ajax() should not be empty!!Failed asserting that a string is not empty.

/usr/home/hubert/tmp/php/equal_compare.php:24

Page 18: Test in action   week 2

xUnit Architecture

• Test Case• Test fixtures– Pre-action / Post-action needed to run a test

• Test Suites– A set of tests that all share the same fixture– The order of the tests shouldn't matter

Page 19: Test in action   week 2

Test Fixtures

• Fixtures– Avoid duplicate Arrangement code– Make test cases focus on Action and Assertion

• Test Fixtures– setUp()• Pre-action before each test case

– tearDown()• Post-action after each test case

Page 20: Test in action   week 2

Test Execution

Page 21: Test in action   week 2

Fixture Example

• Test Codeclass StackTest extends PHPUnit_Framework_TestCase { protected $stack;

protected function setUp() { $this->stack = array(); }

public function testEmpty() { $this->assertTrue(empty($this->stack)); }

public function testPush() { array_push($this->stack, 'foo'); $this->assertEquals('foo', $this->stack[count($this->stack)-1]); $this->assertFalse(empty($this->stack)); }

public function testPop() { array_push($this->stack, 'foo'); $this->assertEquals('foo', array_pop($this->stack)); $this->assertTrue(empty($this->stack)); }}

Page 22: Test in action   week 2

Fixture Guideline

• Fixture Guideline– Only use setUp and tearDown to initialize or

destroy objects that are shared throughout the test class in all the tests• Otherwise, readers don’t know which tests use the

logic inside the setup method and which don’t

Page 23: Test in action   week 2

Sharing Fixture

• Sharing Fixture– Really few reason to share fixtures– Good example

• Reuse database connection

– Sample Test Codeclass DatabaseTest extends PHPUnit_Framework_TestCase { protected static $dbh;

public static function setUpBeforeClass() { self::$dbh = new PDO('sqlite::memory:'); }

public static function tearDownAfterClass() { self::$dbh = NULL; }}

Page 24: Test in action   week 2

Organize PHPUnit Tests

• Mapping for production code and testtests|── _log|── bootstrap.php|── handlers│ └── _details│ |── TRConverterTest.php│ └── tmql│ └── TMQLEscapeTest.php|── lib└── phpunit.xml

middleware_rev |── handlers│ └── _details│ |── TRConverter.class.php│ └── tmql│ └── TMQLEscape.class.php└── lib

Page 25: Test in action   week 2

Execute PHPUnit tests

• Execute all tests% phpunit

• Execute all tests in a subdirectory% phpunit handlers

• Execute single test in a subdirectory % phpunit --filter TMQLEscapeTest handlers

Page 26: Test in action   week 2

Test Naming

• Test Class Name– For class name “Util”– Test class name should be “UtilTest”– Test filename should be “UtilTest.php”

Page 27: Test in action   week 2

Test Naming

• Function Name– Test function name should be

test_<function>_<scenario>_<expect_behavior>– Example• test_escape_evenBackSlashesData_successEscape

Page 28: Test in action   week 2

Single Assertion / Concept per Test

• Single Assertion / Concept per Test– If a test failed, the cause may be more obvious– Compare• PHPUnit Example• Fixture Example

– testPushPop test 3 concepts• Test for Empty / Push / Pop

Page 29: Test in action   week 2

Clean Test

• Clean Test– Keeping Tests Clean– Or you will not maintain them– Test codes are as important code as production– Write Test API / Utility / DSL– Clean TDD cheat sheet• http://www.planetgeek.ch/2011/01/04/clean-code-and

-clean-tdd-cheat-sheets/

Page 30: Test in action   week 2

F.I.R.S.T

• F.I.R.S.T– Fast– Independent (isolated)– Repeatable– Self-Validating– Timely

Page 31: Test in action   week 2

References

• Clean Code• The Art of Unit Testing