2. WHAT IS UNIT TESTING…
and why is it a Good Thing™?
3. WHAT IS UNIT TESTING?
“In computer programming, unit testing is a method by
which individual units of source code are tested to
determine if they are fit for use. A unit is the smallest
testable part of an application.” Wikipedia
4. HAVE ANY OF THESE
EVER APPLIED TO YOU?
You have a piece of code that everyone is too
terrified to touch.
You’re too scared to refactor or change a piece of
code because you can’t predict the impact it will
have on your application.
Releases are a complete nightmare.
You’ve had to work late or through a weekend to
track down a bug.
6. …BUT WORTHWHILE
A study conducted by Microsoft and IBM showed
writing tests can add 15%-35% to development time
but reduce the number of bugs by 40%-90%!
Writing code that is easily testable encourages best
practices, such as SOLID principles.
Having a set of unit tests can help you make sure
your deployments are painless rather than painful
None of us want to be stuck at work all weekend
trying to work out why a code change has broken
the whole application.
8. INTRODUCTION TO
PHPUNIT
PHPUnit is a unit testing framework written in
PHP, created by Sebastian Bergman.
Part of the xUnit family of testing frameworks.
While there are other unit testing frameworks for
PHP (such as SimpleTest or Atoum) PHPUnit has
become the de facto standard.
Major frameworks, such as Zend, Symfony and
Cake, and many other PHP projects such as Doctrine
have test suites written with PHPUnit.
10. REQUIREMENTS
Minimum requirement is PHP 5.2.7 but 5.3.X is
recommended.
If you want code coverage analysis (you do!) you
need to install the PECL xDebug extension.
Best installed via the PEAR installer so you need to
have run the pear installation.
11. INSTALLING VIA PEAR
If installing via PEAR you need two commands to
get up and running:
Full installation instructions (including other
optional PHPUnit modules) can be found at
http://www.phpunit.de/manual/3.6/en/installatio
n.html
13. TEST WRITING BEST
PRACTICES
The general aim is to make sure every possible path
through your code is exercised at least once in a test.
This means you need to write tests that exercise error
conditions too.
Rule of thumb: one test method per expected
outcome per method tested.
Have descriptive test method names.
Name the test class after the class being tested.
14. TEST BASICS
Simply add ‘require_once PHPUnit/Autoload.php’ to each test
file.
A PHPUnit test is a class that (usually) extends
PHPUnit_Framework_TestCase.
The class name should end with the word ‘Test’, e.g. ‘FooBarTest’.
Each test class should be in its own file named after the class, e.g.
‘FooBarTest.php’.
Each test method name must begin with the word ‘test’, e.g.
‘testSomethingWorks’ or have an @test annotation.
Test methods must be public.
The class must contain one or more methods that perform tests or
the test case will fail.
A test method must contain one or more assertions, be marked as
incomplete or skipped.
15. TEST FIXTURES
A fixture in a test is something (usually an object) that you want
to test.
Also known as System Under Test (SUT).
PHPUnit will set up fixtures for you if you add protected
methods setUp and optionally tearDown in your test class.
You provide code to create/destroy fixtures in these methods.
These methods are called before and after each test method so
that each test runs on fresh fixtures.
setUpBeforeClass and tearDownAfterClass are also available.
These are run once at the beginning and end of the test class.
16. WRITING ASSERTIONS
Assertions are used to test expected behaviour from
your SUT.
PHPUnit provides many different assertions for all
sorts of needs, e.g.
assertEquals, assertEmpty, assertTrue, assertType, et
c.
You can also test output using expectOutputString.
More complicated assertions can be constructed
using assertThat.
For a test to pass all assertions must evaluate to true.
17. ANNOTATIONS
PHPUnit supports annotations to give instructions to
the test method being executed.
Annotations are included in block comments before
the method and always begin with an ‘@’.
Examples:
@depends, @expectedException, @dataProvider.
Full details on supported annotations at
http://www.phpunit.de/manual/3.6/en/appendix
es.annotations.html
18. DATA PROVIDERS
A data provider is a method that returns an array of
values to use in a test.
PHPUnit will call the related test method once for
each set of data, passing the values as arguments to
the method.
Set using the @dataProvider annotation.
Allows you to easily add extra values to test with.
Also makes tests shorter and more concise by
keeping values to test with out of test methods.
19. TESTING EXCEPTIONS
You can tell PHPUnit that a test should expect an
exception.
This can be done in two ways:
Through the method
setExpectedException($exception, $message = ‘’, $code
= null)
Through
@expectedException, @expectedExceptionMessage, @e
xpectedExceptionCode annotations.
PHP errors such as warnings are converted into
exceptions by PHPUnit. These can also be tested for.
20. MOCK OBJECTS
One of the most powerful features of PHPUnit.
21. WTF IS A MOCK OBJECT?
Allows you to replace a dependency of your SUT with an
object that has predefined behaviour.
The mock object becomes part of the test. If the methods
defined are not called as expected the test fails.
Proper use of mock objects allow you to make sure you’re
only testing the SUT and not other code.
Helps to ensure that if a test fails it’s in the SUT, not a
dependency.
However, you need to be using Dependency Injection to
use mock objects.
22. MOCK OBJECT BASICS
PHPUnit creates a mock by sub-classing the original
object.
Once you have a mock object you can define what
methods you expect to be called on it, with what
arguments and what the mock should do.
23. OTHER MOCK OBJECT
USES
Mock objects allow you to test concrete methods of
abstract classes with getMockForAbstractClass.
You can create a mock object representing a SOAP
web service using getMockFromWsdl.
PHPUnit has experimental support for mocking out
file system calls using the package vfsStream.
More information at
http://www.phpunit.de/manual/3.6/en/test-
doubles.html.
25. COMMAND LINE RUNNER
Tests are normally run from the command line with the
phpunit command.
Just typing phpunit will get a ‘help’ output.
Passing the name of the test will run just that test.
You can also pass a path to a directory to run all tests in it
or the name of a test file to run tests in that file.
PHPUnit prints a ‘.’ for each test passed, ‘F’ for a
failure, ‘E’ for an error, ‘I’ for incomplete or ‘S’ for
skipped.
More information is also printed for anything other than a
pass.
27. OTHER WAYS TO RUN
TESTS
Many IDE’s such as Zend Studio include PHPUnit
integration. This enables you to write and run tests
from within the IDE.
Running tests can be integrated into continuous
integration servers such as Jenkins.
In this case your full test suite can be run
automatically with each edit to your code.
Any test failure will mean the build fails.
28. CODE COVERAGE
ANALYSIS…
or how to make sure you’re not feeling a false sense of security.
29. WTF IS CODE
COVERAGE?
Code coverage tells you how much of your code is
covered by tests.
PHPUnit can generate code coverage reports in a number
of formats including HTML but…
You must have installed xDebug. (pecl install xdebug)
Helps to avoid a false sense of security.
Code coverage threshold percentage can be added to
continuous integration builds.
Add code coverage by passing the –coverage-xxx
option, eg. phpunit –coverage-html ./reports ./
31. INTRO TO EXTENSIONS
PHPUnit supports a number of extensions that allow
you to write specialised tests.
These include working with
databases, Selenium, and running profiling with
XHProf.
Full details at
http://www.phpunit.de/manual/3.6/en/installatio
n.html.
32. TESTING WITH
DATABASES
To do this install the DbUnit You need to provide a
extension, eg. ‘pear install schema with tables for
phpunit/DbUnit’ PHPUnit to use.
However, where possible getConnection must return a
PDO instance for PHPUnit
avoid tests using a database to use.
by using mock objects.
getDataSet returns data to
Test case must extend populate database tables
‘PHPUnit_Extensions_Datab with.
ase_TestCase’. PHPUnit truncates tables
Defines two extra methods before each test run and
that you must implement: inserts data. This means
getConnection and each test runs with a fresh
set of predictable data.
getDataSet.
34. ADDING A CONFIG FILE
Options can be passed to PHPUnit through the command
line but it also supports adding an XML config file.
This can include a number of options such as where to
find test cases and which directories to include for code
coverage analysis.
To use this just create the file and name it
phpunit.xml, adding it to the root of your tests directory.
Especially useful when running tests as part of a CI build.
Full details at
http://www.phpunit.de/manual/3.6/en/appendixes.co
nfiguration.html
Ask who has written tests before. Ask about experience with PHPUnit.
Single Responsibility PrincipleOpen/Closed PrincipleLiskov Substitution PrincipleInterface Segregation PrincipleDependency Inversion Principle
Emphasise that it is a framework like other frameworks. You still need to write the 20% to have your own tests!
Discuss that this only works if the pear command has been added to your path.
Mention that the require_once call will only work if the path to the pear installation dir has been added to PHP’s include path.Mention that casing is important. Also mention that defaults (use of word test, etc) can be overridden in config, command line switches, etc.Mention that you can have as many methods as you like in a test class but only test* methods will be run as tests.
Mention cases where setUpBeforeClass and tearDownAfterClass are useful.
Mention annotations similar to doc blox in PHP.
Explain that fatal errors cannot be converted to exceptions. Give an example where a warning could be caught, such as a call to fopen that fails on a non-existent file. Explain that PHPUnit registers its own error handler.
Switch to browser to show sample code coverage report.
Mention supported formats of data such as CSV and XML.