Prev Next

Chapter 16. Other Uses for Tests

Once you get used to writing automated tests, you will likely discover more uses for tests. Here are some examples.

Agile Documentation

Typically, in a project that is developed using an agile process, such as Extreme Programming, the documentation cannot keep up with the frequent changes to the project's design and code. Extreme Programming demands collective code ownership, so all developers need to know how the entire system works. If you are disciplined enough to consequently use "speaking names" for your tests that describe what a class should do, you can use PHPUnit's TestDox functionality to generate automated documentation for your project based on its tests. This documentation gives developers an overview of what each class of the project is supposed to do.

PHPUnit's TestDox functionality looks at a test class and all the test method names and converts them from camel case PHP names to sentences: testBalanceIsInitiallyZero() becomes "Balance is initially zero". If there are several test methods whose names only differ in a suffix of one or more digits, such as testBalanceCannotBecomeNegative() and testBalanceCannotBecomeNegative2(), the sentence "Balance cannot become negative" will appear only once, assuming that all of these tests succeed.

Let us take a look at the agile documentation generated for the BankAccount class (from Example 13.1):

phpunit --testdox BankAccountTest
PHPUnit 3.5.13 by Sebastian Bergmann.

BankAccount
 [x] Balance is initially zero
 [x] Balance cannot become negative

Alternatively, the agile documentation can be generated in HTML or plain text format and written to a file using the --testdox-html and --testdox-text arguments.

Agile Documentation can be used to document the assumptions you make about the external packages that you use in your project. When you use an external package, you are exposed to the risks that the package will not behave as you expect, and that future versions of the package will change in subtle ways that will break your code, without you knowing it. You can address these risks by writing a test every time you make an assumption. If your test succeeds, your assumption is valid. If you document all your assumptions with tests, future releases of the external package will be no cause for concern: if the tests succeed, your system should continue working.

Cross-Team Tests

When you document assumptions with tests, you own the tests. The supplier of the package -- who you make assumptions about -- knows nothing about your tests. If you want to have a closer relationship with the supplier of a package, you can use the tests to communicate and coordinate your activities.

When you agree on coordinating your activities with the supplier of a package, you can write the tests together. Do this in such a way that the tests reveal as many assumptions as possible. Hidden assumptions are the death of cooperation. With the tests, you document exactly what you expect from the supplied package. The supplier will know the package is complete when all the tests run.

By using stubs (see the chapter on "Mock Objects", earlier in this book), you can further decouple yourself from the supplier: The job of the supplier is to make the tests run with the real implementation of the package. Your job is to make the tests run for your own code. Until such time as you have the real implementation of the supplied package, you use stub objects. Following this approach, the two teams can develop independently.

Prev Next
1. Automating Tests
2. PHPUnit's Goals
3. Installing PHPUnit
4. Writing Tests for PHPUnit
Test Dependencies
Data Providers
Testing Exceptions
Testing PHP Errors
Assertions
assertArrayHasKey()
assertClassHasAttribute()
assertClassHasStaticAttribute()
assertContains()
assertContainsOnly()
assertEmpty()
assertEqualXMLStructure()
assertEquals()
assertFalse()
assertFileEquals()
assertFileExists()
assertGreaterThan()
assertGreaterThanOrEqual()
assertInstanceOf()
assertInternalType()
assertLessThan()
assertLessThanOrEqual()
assertNull()
assertObjectHasAttribute()
assertRegExp()
assertStringMatchesFormat()
assertStringMatchesFormatFile()
assertSame()
assertSelectCount()
assertSelectEquals()
assertSelectRegExp()
assertStringEndsWith()
assertStringEqualsFile()
assertStringStartsWith()
assertTag()
assertThat()
assertTrue()
assertType()
assertXmlFileEqualsXmlFile()
assertXmlStringEqualsXmlFile()
assertXmlStringEqualsXmlString()
5. The Command-Line Test Runner
6. Fixtures
More setUp() than tearDown()
Variations
Sharing Fixture
Global State
7. Organizing Tests
Composing a Test Suite Using the Filesystem
Composing a Test Suite Using XML Configuration
8. TestCase Extensions
Testing Output
9. Database Testing
Supported Vendors for Database Testing
Difficulties in Database-Testing
The four stages of a database test
1. Clean-Up Database
2. Set up fixture
3–5. Run Test, Verify outcome and Teardown
Configuration of a PHPUnit Database TestCase
Implementing getConnection()
Implementing getDataSet()
What about the Datatabase Schema (DDL)?
Tip: Use your own Abstract Database TestCase
Understanding DataSets and DataTables
Available Implementations
Beware of Foreign Keys
Implementing your own DataSets/DataTables
The Connection API
Database Assertions API
Asserting the Row-Count of a Table
Asserting the State of a Table
Asserting the Result of a Query
Asserting the State of Multiple Tables
Frequently Asked Questions
Will PHPUnit (re-)create the database schema for each test?
Am I required to use PDO in my application for the Database Extension to work?
What can I do, when I get a Too much Connections Error?
How to handle NULL with Flat XML / CSV Datasets?
10. Incomplete and Skipped Tests
Incomplete Tests
Skipping Tests
11. Test Doubles
Stubs
Mock Objects
Stubbing and Mocking Web Services
Mocking the Filesystem
12. Testing Practices
During Development
During Debugging
13. Test-Driven Development
BankAccount Example
14. Behaviour-Driven Development
BowlingGame Example
15. Code Coverage Analysis
Specifying Covered Methods
Ignoring Code Blocks
Including and Excluding Files
16. Other Uses for Tests
Agile Documentation
Cross-Team Tests
17. Skeleton Generator
Generating a Test Case Class Skeleton
Generating a Class Skeleton from a Test Case Class
18. PHPUnit and Selenium
Selenium RC
PHPUnit_Extensions_SeleniumTestCase
19. Logging
Test Results (XML)
Test Results (TAP)
Test Results (JSON)
Code Coverage (XML)
20. Extending PHPUnit
Subclass PHPUnit_Framework_TestCase
Write custom assertions
Implement PHPUnit_Framework_TestListener
Subclass PHPUnit_Extensions_TestDecorator
Implement PHPUnit_Framework_Test
A. Assertions
B. Annotations
@assert
@author
@backupGlobals
@backupStaticAttributes
@covers
@dataProvider
@depends
@expectedException
@expectedExceptionCode
@expectedExceptionMessage
@group
@outputBuffering
@runTestsInSeparateProcesses
@runInSeparateProcess
@test
@testdox
@ticket
C. The XML Configuration File
PHPUnit
Test Suites
Groups
Including and Excluding Files for Code Coverage
Logging
Test Listeners
Setting PHP INI settings, Constants and Global Variables
Configuring Browsers for Selenium RC
D. Index
E. Bibliography
F. Copyright