Unit Testing using PHPUnit

Post on 17-May-2015

3.683 views 11 download

Tags:

Transcript of Unit Testing using PHPUnit

PHPUnitAutomated Unit Testing Framework.

By : Varun TaliyanOSSCube Solutions Pvt. Ltd.

Unit Test Unit : The smallest testable part of an

application. Unit testing : Testing a unit of code

isolated from its dependencies. Testing with PHPUnit : The difference is

between testing, that is, checking that your program behaves as expected, and performing a battery of tests, runnable code-fragments that automatically test the correctness of parts (units) of the software.

PHPUnit Part of xUnit family(JUnit, Sunit,...) Created by Sebastian Bergmann Integrated in most IDE

Eclipse, Netbeans, Zend Stuide, PHPStorm Integrated/supported

Zend Studio, Zend Framework, Cake, Symfony

PHPUnit's Goals

Tests should be: Easy to learn to write. Easy to write. Easy to read. Easy to execute. Quick to execute. Isolated. Composable.

Resolve conflicts: Easy to learn to write versus easy to write. Isolated versus quick to execute.

Installing PHPUnit PHPUnit is installed using the PEAR

Installer Commands to install :

pear config-set auto_discover 1 pear install pear.phpunit.de/PHPUnit

Writing Tests for PHPUnit The tests for a class Class go into a class

ClassTest. ClassTest inherits (most of the time) from

PHPUnit_Framework_TestCase. The tests are public methods that are

named test*. Inside the test methods, assertion

methods such as assertEquals() are used to assert that an actual value matches an expected value.

Sample PHP class for testing//Filename : user.php<?phpclass User { protected $name; public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function talk() { return "Hello world!"; }}?>

Test class for testing user.php

<?phprequire_once "PHPUnit/Autoload.php";require_once "user.php";

class UserTest extends PHPUnit_Framework_TestCase{}?>

Test class for testing user.php

<?php...class UserTest extends PHPUnit_Framework_TestCase{ // test the talk method public function testTalk() { // make an instance of the user $user = new User(); // use assertEquals to ensure the greeting is what you expect $expected = "Hello world!"; $actual = $user->talk(); $this->assertEquals($expected, $actual); }}

The Command-Line Test Runner The PHPUnit command-line test runner

can be invoked through the phpunit command.

phpunit UnitTest UnitTest.php Runs the tests that are provided by the class UnitTest. This class is expected to be declared in the specified sourcefile.

Running our Tests

root@varuntaliyan:/var/www/test-1# phpunit userTest.phpPHPUnit 3.6.10 by Sebastian Bergmann..

Time: 0 seconds, Memory: 2.75Mb

OK (1 test, 1 assertion)

For each test run, the PHPUnit command-line tool prints one character to indicate progress:

. – Printed when a test succeeds. F – Printed when an assertion fails. E – Printed when an error occurs while

running the test. S – Printed when the test has been

skipped. I – Printed when the test is marked as

being incomplete.

Output when a Test fails

root@varuntaliyan:/var/www/test-1# phpunit userTest.php

PHPUnit 3.6.10 by Sebastian Bergmann.

FaTime: 0 seconds, Memory: 2.75Mb

There was 1 failure:

1) UserTest::testTalkFailed asserting that two strings are equal.--- Expected+++ Actual@@ @@-'Hello world!'+'Non sense'

/var/www/test-1/userTest.php:14

FAILURES!Tests: 1, Assertions: 1, Failures: 1.

Test Dependencies

PHPUnit supports the declaration of explicit dependencies between test methods. Such dependencies do not define the order in which the test methods are to be executed but they allow the returning of an instance of the test fixture by a producer and passing it to the dependent consumers.

A producer is a test method that yields its unit under test as return value.

A consumer is a test method that depends on one or more producers and their return values.

Using the @depends annotation to express dependencies

<?phpclass StackTest extends PHPUnit_Framework_TestCase{ public function testEmpty() { $stack = array(); $this->assertEmpty($stack); return $stack; } /** * @depends testEmpty */ public function testPush(array $stack) { array_push($stack, 'foo'); $this->assertEquals('foo', $stack[count($stack)-1]); $this->assertNotEmpty($stack); return $stack; } /** * @depends testPush */ public function testPop(array $stack) { $this->assertEquals('foo', array_pop($stack)); $this->assertEmpty($stack); }}?>

Running the Test

:/var/www/test-1# phroot@varuntaliyanpunit depend.php PHPUnit 3.6.10 by Sebastian Bergmann.

...

Time: 0 seconds, Memory: 2.75Mb

OK (3 tests, 5 assertions)

Data Providers

A test method can accept arbitrary argumeants. These arguments are to be provided by a data provider methods.

Using a data provider that returns an array of arrays

<?phpclass 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) ); }}?>

Testing Exceptions : Tests whether an exception is

thrown inside the tested code.

//Filename : exceptionclass.php<?phpini_set('display_errors', 1);class myexcepclass extends Exception {function checkNum($number) { if($number>1) { throw new Exception("Value must be 1 or below"); } return true; }}?>

Test class for exceptionclass.php

<?phprequire_once '/usr/share/php/PHPUnit/Framework/TestCase.php';require_once 'exceptionclass.php';class myexcepclassTest extends PHPUnit_Framework_TestCase {/** * @expectedException InvalidArgumentException: */

public function testcheckNum() {$obj = new MyCustomException;$obj->checkNum(2);

}}?>

Running the test PHPUnit 3.6.10 by Sebasroot@varuntaliyan:/var/www/tests/error# phpunit testexceptionclass.php tian Bergmann.FTime: 0 seconds, Memory: 2.75Mb

There was 1 failure:

1) myexcepclassTest::testcheckNumFailed asserting that exception of type "Exception" matches expected exception "InvalidArgumentException:".

FAILURES!Tests: 1, Assertions: 1, Failures: 1.

Testing Output : Sometimes you want to assert that the execution of a method, for instance, generates an expected output

//Filename : outputclass.php<?phpini_set('display_errors', 1);class Myoutputclass {function greetings() {

print 'Hello Everyone'; }function quote() {

print 'Its morning again'; }}?>

Test class for outputclass.php

//Filename : testoutputclass.php<?phprequire_once '/usr/share/php/PHPUnit/Framework/TestCase.php';require_once 'outputclass.php';

class outputclassTest extends PHPUnit_Framework_TestCase{ protected $obj;

protected function setUp() { $this->obj = new Myoutputclass; }

public function testgreetings() {

$this->expectOutputString('Hello Everyone');

$this->obj->greetings();

}

public function testquote() {

$this->expectOutputString('Its noon');

$this->obj->quote(); } }?>

Running the test

root@varuntaliyan:/var/www/tests/output# phpunit testoutputclass.php PHPUnit 3.6.10 by Sebastian Bergmann.

.F

Time: 0 seconds, Memory: 2.75Mb

There was 1 failure:

1) outputclassTest::testquoteFailed asserting that two strings are equal.--- Expected+++ Actual@@ @@-'Its noon'+'Its morning again'

FAILURES!Tests: 2, Assertions: 2, Failures: 1.

Assertions assertArrayHasKey() assertContains() assertContainsOnly() assertCount() assertEmpty() assertEquals() assertFalse() assertClassHasAttribute() assertClassHasStaticAttribute().....

assertGreaterThan()

assertGreaterThanOrEqual()

assertInstanceOf()

assertInternalType()

assertLessThan()

assertLessThanOrEqual()

assertNull()

assertRegExp()

assertSame()

assertStringEndsWith()

assertStringStartsWith()......

Fixtures is a “known state” of an application need to be “set up” at the start of test need to be “torn down” at the end of the

test shares “states” over test methods setUp() is where you create the objects

against which you will test. tearDown() is where you clean up the

objects against which you tested. More setUp() than tearDown()

Using setUp() to create the stack fixture<?phpclass 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)); }}?>

PHPUnit – Database Extension PHPUnit Database Extension – DBUnit Port Can be installed by : pear install

phpunit/DbUnit Currently supported databases:

MySQL PostgreSQL Oracle SQLite has access to other database systems such as IBM

DB2 or Microsoft SQL Server Through Zend Framework or Doctrine 2 integrations

The four stages of a database test

1.Set up fixture2.Exercise System Under Test3.Verify outcome4.Teardown

Configuration of a PHPUnit Database TestCase

Need to Extend abstract TestCase : PHPUnit_Extensions_Database_TestCase

require_once 'PHPUnit/Extensions/Database/TestCase.php';

class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase

{}

Configuration of a PHPUnit Database TestCase

Must Implement getConnection() - Returns a database

connection wrapper.getDataSet() - Returns the dataset to seed

the database with.

Implementation of getConnection() and getDataset() methods

<?phprequire_once 'PHPUnit/Extensions/Database/TestCase.php'; class DatabaseTest extends PHPUnit_Extensions_Database_TestCase{ protected function getConnection() { $pdo = new PDO('mysql:host=localhost;dbname=testdb', 'root', ''); return $this->createDefaultDBConnection($pdo, 'testdb'); } protected function getDataSet() { return $this->createFlatXMLDataSet(dirname(__FILE__).'/_files/bank-account-seed.xml'); }}?>

Test class for database testing//Filename : dbclass.php<?phpclass BankAccount {public function __construct($accno, $conn, $bal=0) {$this->addData(array($accno,$bal),$conn);}function addData($data, $conn) {$sql = "INSERT INTO bank_account (account_number, balance) VALUES (:acc,:bal)";$q = $conn->prepare($sql);$q->execute(array(':acc'=>$data[0], ':bal'=>$data[1]));}}

Test case for dbclass.php <?phprequire_once 'PHPUnit/Extensions/Database/TestCase.php';require_once "dbclass.php";class BankAccountDBTest extends PHPUnit_Extensions_Database_TestCase{ protected $pdo; public function __construct() {

$this->pdo = new PDO('mysql:host=localhost;dbname=phpunitdb', 'root', 'root'); } protected function getConnection() { return $this->createDefaultDBConnection($this->pdo, 'phpunitdb'); } protected function getDataSet() { return $this->createFlatXMLDataSet('/var/www/tests/bankaccdb/files/seed.xml'); } public function testaddData() { $bank_account = new BankAccount('1234567', $this->pdo); $xml_dataset = $this->createFlatXMLDataSet('/var/www/tests/bankaccdb/files/seed-after-insert.xml'); $this->assertTablesEqual($xml_dataset->getTable('bank_account'),$this->getConnection()->createDataSet()->getTable('bank_account')); }}

Running the test root@varuntaliyan:/var/www/tests/bankaccdb# phpunit dbclasstest.php PHPUnit 3.6.10 by Sebastian Bergmann..Time: 0 seconds, Memory: 3.00Mb

OK (1 test, 1 assertion)

Output when a Test failsroot@varuntaliyan:/var/www/tests/bankaccdb# phpunit dbclasstest.php PHPUnit 3.6.10 by Sebastian Bergmann.FTime: 0 seconds, Memory: 3.00MbThere was 1 failure:1) BankAccountDBTest::testaddDataFailed asserting that +----------------------+----------------------+| bank_account |+----------------------+----------------------+| account_number | balance |+----------------------+----------------------+| 1593490 | 100 |+----------------------+----------------------+| 1593648 | 1216 |+----------------------+----------------------+| 1234861 | 89 |+----------------------+----------------------+| 1593648 | 1216 |+----------------------+----------------------+| 1234567 | 0 |+----------------------+----------------------+

is equal to expected

+----------------------+----------------------+

| bank_account |

+----------------------+----------------------+

| account_number | balance |

+----------------------+----------------------+

| 1593490 | 100.00 |

+----------------------+----------------------+

| 1593648 | 1216.00 |

+----------------------+----------------------+

| 1234861 | 89.00 |

+----------------------+----------------------+

| 1593648 | 1216.00 |

+----------------------+----------------------+

/var/www/tests/bankaccdb/dbclasstest.php:29

FAILURES!

Tests: 1, Assertions: 1, Failures: 1.

Thank you - Resources http://

www.phpunit.de/manual/3.6/en/index.html

http://www.ds-o.com/archives/63-PHPUnit-Database-Extension-DBUnit-Port.html