The document discusses PHPUnit, a testing framework for PHP. It provides an overview of PHPUnit, including that it was created by Sebastian Bergmann in 2004 as a port of xUnit to PHP. PHPUnit uses assertions for testing and supports unit, integration, and acceptance testing. The document reviews available assertions, annotations like @group and @dataProvider, and how to set up and run tests with PHPUnit.
3. Michelangelo van Dam
PHP Consultant, Community Leader & Trainer
https://www.flickr.com/photos/akrabat/8784318813
4. Create, Test, Secure, Repeat
Workshop
Get prepared
https://github.com/in2it/ctsr-workshop
Requirements
5.4+
Requirements
- a computer with PHP 5.4 or higher
- the latest composer
- git
Exercises tested on
- Microsoft Windows 7 & 8
- Linux
- Mac OS X 10.10.2 or higher
Learn unit testing like a pro
6. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
7. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
8. PHPUnit
• Created by Sebastian
Bergmann in 2004
• Port of xUnit to PHP
• Uses assertions for testing
• Supports
• Unit testing
• Integration testing w/ DBUnit
• Acceptance testing w/
Selenium
15. Who created PHPUnit and is
now project lead?
A. Chris Hartjes
B. Sebastian Bergmann
C. Stefan Priepsch
16. With PHPUnit you can…?
A. Test the smallest functional piece of code (unit)
B. Test integrations with a database (integration)
C. Test automated acceptance testing with Selenium
D. All of the above
E. None of the above
17. An assertion is…?
A. Verifying that an expected value matches the
result of a process?
B. Verifying that a process produces results
C. A transformation of a value
18. Assertion
• is a true/false statement
• to match an expectation
• with the result of functionality under test
25. How to use @group
# Run phpunit only against tests for the Order module
./vendor/bin/phpunit --group Order
# Run phpunit for all tests except for the Order module
./vendor/bin/phpunit --exclude-group Order
31. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
35. For this training
Installation of source code
Clone the repository into your workspace before attending the workshop.
git clone https://github.com/in2it/ctsr-workshop.git
cd ctsr-workshop/
Once you have cloned the training package, make sure you install composer.
curl -sS https://getcomposer.org/installer | php
When the download is done, install required components using composer
php composer.phar install
36. For this training
Installation of source code
Clone the repository into your workspace before attending the workshop.
git clone https://github.com/in2it/ctsr-workshop.git
cd ctsr-workshop/
Once you have cloned the training package, make sure you install composer.
curl -sS https://getcomposer.org/installer | php
When the download is done, install required components using composer
php composer.phar install
https://www.flickr.com/photos/intelfreepress/13983474320
37. During the workshop you're asked to solve several exercises. All example codes
are based on a UNIX-like OS, so if you plan to participate this workshop with
another OS, you need to know what changes are required to have the exercises
run on your operating system.
The exercises, the source code and the examples are tested on the following
platforms:
• Windows 7
• Mac OS X
• Ubuntu Linux
When you need to switch to a specific exercise branch (e.g. ex-0.0), you can do
this with the following command.
git checkout -b ex-0.0 origin/ex-0.0
41. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
45. Exercise 0.0
• What will happen when you run PHPUnit now?
• Checkout branch ex-0.0
git checkout -b ex-0.0 origin/ex-0.0
php composer.phar dump-autoload
• Run PHPUnit
46.
47. Let’s write our first test
<?php
namespace In2itTestWorkshopCtsr;
use In2itWorkshopCtsrSampleClass;
class SampleClassTest extends PHPUnit_Framework_TestCase
{
public function testSomethingReturnsGreeting()
{
$sampleClass = new SampleClass();
$this->assertSame(
'Hello World!', $sampleClass->doSomething()
);
}
}
48. Exercise 0.1
• What will happen when you run PHPUnit now?
• Checkout branch ex-0.1
git checkout -b ex-0.1 origin/ex-0.1
php composer.phar dump-autoload
• Run PHPUnit
49. Error?
Got Error?
error: Your local changes to the following files would be overwritten by checkout:
composer.lock
Please, commit your changes or stash them before you can switch branches.
Aborting
Solution
git checkout -- composer.lock
git checkout -b ex-0.1 origin/ex-0.1
52. Exercise 0.2
• What will happen when you run PHPUnit now?
• Checkout branch ex-0.2
git checkout -b ex-0.2 origin/ex-0.2
php composer.phar dump-autoload
• Run PHPUnit
53.
54. Exercise 0.3
• Test that you can provide an argument and the
argument will be returned as “Hello <arg>!”
• Write the test
• Modify the class
55. Modifying the test class
public function testSomethingReturnsArgument()
{
$sampleClass = new SampleClass();
$argument = 'Class';
$this->assertSame(
sprintf('Hello %s!', $argument),
$sampleClass->doSomething($argument)
);
}
61. Chapter 0
What have you learned
• How to install phpunit
• How to configure phpunit
• How to write your test first
• How to modify requirements through testing
• How to debug failures and fix them easily with tests
63. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
66. Functional requirements
• Application needs to manage cron entries, where
all scheduled tasks are stored in a database and
written to the crontab when saved.
67. What is crontab?
• A tool on UNIX-like systems to execute tasks at a certain interval
• Each line contains the following items:
• Minutes and/or interval
• Hours and/or interval
• Days of the month (DOM) and/or interval
• Months and/or interval
• Days of the week (DOW) and/or interval
• Executable command
68. Example crontab
# Minutes Hours DOM Months DOW Command
# Warm up caches with new products
# Every 5 minutes each day
*/5 * * * * /bin/sh /path/to/productCollector.sh 2>&1
# Send marketing mail to active customers
# Every Monday at 9:30am
30 9 * * 1 /usr/bin/php /path/to/marketingMailSender.php 2>&1
# Clean up waste
# Every day at 6am, 1pm and 5pm from Monday to Friday
0 6,13,17 * * 1-5 /bin/sh /path/to/wasteCleaner.sh 2>&1
69. Analysis
• crontab = collection of entries
• Each entry contains 5 assets and a command
• Each asset can contain a
• Wildcard (full range)
• Range n-m (subset of full range)
• List n,m,o
• A single value n
• With similar intervals (without the wildcard)
71. • cronmanager
• collection of crontab entries
• each entry contains
• minutes (collection) and interval (collection)
• hours (collection) and interval (collection)
• days of the month (collection) and interval (collection)
• months (collection) and interval (collection)
• days of the week (collection) and interval (collection)
• command string
• each entry collection (minutes, hours, dom, months, dow) requires a range
• minutes (0 - 59)
• hours (0 - 23)
• days of the month (1 - 31)
• month (1 - 12)
• days of the week (0 - 7) (0 & 7 are Sunday)
• crontab is write-only, so we need to update the full crontab completely
79. Something like this… (2)
public function testEntryContainsAllFields()
{
$entry = new Entry();
$this->assertCount(0, $entry->getMinutes());
$this->assertCount(0, $entry->getHours());
$this->assertCount(0, $entry->getDom());
$this->assertCount(0, $entry->getMonths());
$this->assertCount(0, $entry->getDow());
$this->assertSame('', $entry->getCommand());
}
80. Something like this… (3)
public function testEntryCanSetEntryElements()
{
$assetCollection = $this->getMock(
'In2itWorkshopCtsrCronManagerAssetCollection'
);
$entry = new Entry();
$entry->setMinutes($assetCollection);
$this->assertInstanceOf(
'In2itWorkshopCtsrCronManagerAssetCollection',
$entry->getMinutes()
);
/*
* Similar routines for Hours, Days of the Month, Months and Days of the week
*/
$command = $this->getMock('In2itWorkshopCtsrCronManagerCommand');
$entry->setCommand($command);
$this->assertInstanceOf(
'In2itWorkshopCtsrCronManagerCommand',
$entry->getCommand()
);
}
89. Create some bad data
public function badDataProvider()
{
return array (
array ('foo'),
array (new stdClass()),
array (array ()),
array (1.50),
);
}
90. And let’s test it!
/**
* @dataProvider badDataProvider
* @covers In2itWorkshopCtsrCronManagerAsset::__construct
* @covers In2itWorkshopCtsrCronManagerAsset::setValue
* @covers In2itWorkshopCtsrCronManagerAsset::getValue
* @expectedException InvalidArgumentException
*/
public function testRejectBadData($badData)
{
$asset = new Asset($badData);
$this->fail('Expected InvalidArgumentException to be thrown');
}
95. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
97. Legacy code
• Code that was already written
• Not (always) adhering to best
practices
• Not (always) testable
• What developers hate working
on
https://www.flickr.com/photos/archer10/7845300746
150. Let’s use the static
$params = array (
'moduleName' => 'Foo_Bar',
'minVersion' => 0,
'maxVersion' => 1,
'maxOk' => true,
);
// We use a static method for this test
$dependency = Dependency::requires_range(
$params['moduleName'],
$params['minVersion'],
$params['maxVersion'],
$params['maxOk']
);
// We use reflection to see if properties are set correctly
$reflectionClass = new ReflectionClass('Dependency');
151. Use the reflection to assert
// Let's retrieve the private properties
$moduleName = $reflectionClass->getProperty('module_name');
$moduleName->setAccessible(true);
$minVersion = $reflectionClass->getProperty('version_min');
$minVersion->setAccessible(true);
$maxVersion = $reflectionClass->getProperty('version_max');
$maxVersion->setAccessible(true);
$maxOk = $reflectionClass->getProperty('compare_max');
$maxOk->setAccessible(true);
// Let's assert
$this->assertEquals($params['moduleName'], $moduleName->getValue($dependency),
'Expected value does not match the value set’);
$this->assertEquals($params['minVersion'], $minVersion->getValue($dependency),
'Expected value does not match the value set’);
$this->assertEquals($params['maxVersion'], $maxVersion->getValue($dependency),
'Expected value does not match the value set’);
$this->assertEquals('<=', $maxOk->getValue($dependency),
'Expected value does not match the value set');
154. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
168. Some other test tools
https://www.gnu.org/graphics/heckert_gnu.small.png
169. Introduction
Mise en place (preparation)
Running Tests
Starting a new project with TDD
Testing & Improving legacy code
Other tools
Recap & Closing remarks
https://www.flickr.com/photos/ryantylersmith/14010104872
176. in it2PROFESSIONAL PHP SERVICES
Michelangelo van Dam
Zend Certified Engineer
training@in2it.be - www.in2it.be - T in2itvof - F in2itvof
PHPUnit
Getting Started
Advanced Testing
Zend Framework 2
Fundamentals
Advanced
Azure PHP
Quick time to market
Scale up and out
jQuery
Professional jQuery
PHP
PHP for beginners
Professional PHP
HTML & CSS
The Basics
Our training courses