Date post: | 17-May-2015 |
Category: |
Technology |
Upload: | jeremy-cook |
View: | 11,421 times |
Download: | 8 times |
PHPUNIT
From Zero to Hero
WHAT IS UNIT TESTING…
and why is it a Good Thing™?
“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
WHAT IS UNIT TESTING?
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.
HAVE ANY OF THESE EVER APPLIED TO
YOU?
WRITING TESTS IS HARD, WRITING GOOD TESTS IS EVEN
HARDER…
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.
…BUT WORTHWHILE
WHAT IS 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.
INTRODUCTION TO PHPUNIT
INSTALLING PHPUNIT
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.
REQUIREMENTS
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/installation.html
INSTALLING VIA PEAR
WRITING TESTS
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.
TEST WRITING BEST PRACTICES
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.
TEST BASICS
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.
TEST FIXTURES
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, etc.
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.
WRITING ASSERTIONS
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/appendixes.annotations.html
ANNOTATIONS
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.
DATA PROVIDERS
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, @expectedExceptionCode annotations.
PHP errors such as warnings are converted into exceptions by PHPUnit. These can also be tested for.
TESTING EXCEPTIONS
MOCK OBJECTS
One of the most powerful features of PHPUnit.
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.
WTF IS A MOCK OBJECT?
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.
MOCK OBJECT BASICS
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.
OTHER MOCK OBJECT USES
RUNNING TESTS
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.
COMMAND LINE RUNNER
SAMPLE COMMAND LINE OUTPUT
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.
OTHER WAYS TO RUN TESTS
CODE COVERAGE ANALYSIS…
or how to make sure you’re not feeling a false sense of security.
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 ./
WTF IS CODE COVERAGE?
PHPUNIT TEST EXTENSIONS
Writing tests for different situations.
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/installation.html.
INTRO TO EXTENSIONS
TESTING WITH DATABASES
To do this install the DbUnit extension, eg. ‘pear install phpunit/DbUnit’
However, where possible avoid tests using a database by using mock objects.
Test case must extend ‘PHPUnit_Extensions_Database_TestCase’.
Defines two extra methods that you must implement: getConnection and getDataSet.
You need to provide a schema with tables for PHPUnit to use.
getConnection must return a PDO instance for PHPUnit to use.
getDataSet returns data to populate database tables with.
PHPUnit truncates tables before each test run and inserts data. This means each test runs with a fresh set of predictable data.
PHPUNIT CONFIG
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.configuration.html
ADDING A CONFIG FILE
LET’S WRITE SOME TESTS!
QUESTIONS?