About the Author

Chris Shiflett

Hi, I’m Chris, a web craftsman making things like Mapalong & Brooklyn Beta with my friends at Analog.


Who Practices Test-Driven Development (TDD)?

Harry Fuecks maintains a good blog over at Sitepoint and recently wrote a piece on Evaluating PHP Applications.

Noel Darlow, a regular contributor to the Sitepoint forums (and someone whose opinion I respect), comments:

I think testing is a good indicator of the developer's ability. I'll be looking for tests being used to drive the design and not just the odd unit test stuck on after the fact.

I'm a big advocate of testing, and although I won't claim to be an expert on the topic, I have to question whether it's necessary that tests drive the design. It seems plausible that someone could choose to write tests after the implementation, and I don't think ignorance is necessarily the reason.

On the other hand, I find myself taking this approach more and more. For example, when I'm designing a function or class, I start with an example that describes how I want to use it:

<?php 

$auth 
= new myAuth;

$auth->username 'chris';
$auth->password 'mypass';

if (
$auth->checkLogin()) {
    
/* SUCCESS */
} else {
    
/* FAILURE */
}

?>

(Sorry if my ad hoc example doesn't live up to your standards.)

I'll usually type this out at least once, so it's not just imagined. In order to implement myAuth, I can choose to keep this example in mind as I write the code, or I can take this simple example and turn it into a real test or two:

<?php 

include 'test-more.php';

plan(2);

$auth = new myAuth;

{
    
/* Test Valid Credentials */
    
$auth->username 'chris';
    
$auth->password 'mypass';

    
ok($auth->checkLogin(), 'test valid credentials');
}

{
    
/* Test Invalid Credentials */
    
$auth->username 'chris';
    
$auth->password 'notmypass';

    
ok(!$auth->checkLogin(), 'test invalid credentials');
}

?>

It's so easy to write tests, I might even write some for a blank username, blank password, etc. I can do all this without writing a single line of code, and when I begin writing the code, I already have a simple test suite to run - I don't have to write some quick ad hoc tests just to see whether things are working as planned. When all the tests pass, I know I've accomplished my initial design goals.

How many of you test? How many of you write your tests first?

Note: If you happen to be attending PHP Quebec later this week, I'm giving a talk that will discuss some simple approaches to testing.

About this post

Who Practices Test-Driven Development (TDD)? was posted on Tue, 28 Mar 2006 at 03:18:40 GMT. Follow me on Twitter.

0 comments

1.Jon Bridenbaugh said:

I have to confess that I only write these types of tests when I run into a nasty problem. Though I think they should be an integral step in the development process and are not much more effort than pseudo coding and much more useful. Time has to be a factor though.

Tue, 28 Mar 2006 at 04:19:23 GMT Link


2.Greg Beaver said:

I often write failing tests for important bugs in PEAR prior to fixing them, but I find it gets in the way of creative design and effective programming to write them too early - you just end up completely rewriting themand often introducing logic bugs in the abstract implementation because you're thinking in a detailed manner too early in the process. A good design is quickly modified as the abstract requirements' technical realities are better understood, and then once things begin to settle, it is crucial to write proper bounds tests and normal case tests. Only the simplest of designs benefits from pre-coded tests, unless you have unlimited developer time. Believe me - I am not against rewriting tests when implementation changes, I've done this a whole heck of a lot. However, it is important to note that good testing often takes 3 times as long to do as the actual coding, so you need to pick your priorities very carefully for large applications.

Incidentally, I just implemented TAP output for the run-tests command of PEAR for those who like to use it. What it does is save "run-tests.log" in the current directory with TAP-compliant output. In addition to displaying information, when a test fails, it prepends expected/actual output in a #informational directive

This will be in PEAR 1.5.0

Tue, 28 Mar 2006 at 05:03:38 GMT Link


3.Chris Shiflett said:

Thanks for sharing, guys.

Greg, that's very cool that run-tests is going to be capable of producing a TAP-compliant output. Now all four testing approaches of which I'm aware (test-more.php, phpt, Simple-Test, and PHPUnit) support TAP, and that lets PHP developers benefit from the many existing tools that support it, including Apache-Test. Cool. :-)

Tue, 28 Mar 2006 at 05:12:50 GMT Link


4.Noel Darlow (aka McGruff) said:

Hi

I should stress "indicator". It's not a hard and fast rule but I'd expect someone who is up to speed with all the agile stuff to be a fairly sophisticated programmer. I'm definitely going to be interested in what they're doing.

"I have to question whether it's necessary that tests drive the design." (Chris)

Fair point. For me, it's the best way to work I've found - what do others who've tried it think?

I see TDD specifically as the use of mock objects to drive the application design. Although you can create single classes test-first without mocks, the interaction style of testing allows you to "discover" the next layer of objects. By writing a test for one class, I'll define blueprints for its neighbours (the mocks & expectations) which I can come back to implement later. The design ripples out from the point at which you started.

That gives you a lot of freedom. At the same time it's a very focussed way to work all the time guided by clear requirements. While I'm designing I'm also producing real, carefully tested code. It won't be perfect first time. It's assumed there will be a certain amount of refactoring later as you learn more about the design but once again I'll have tests to guide me through that.

Does testing create more work? Well, yes and no. Whenever I've been under pressure and decided to skip the tests I find myself wasting hours trying to track down bugs. I always went back to testing to maintain steady progress. I would have given up prgramming before now otherwise - design is fun but I can't stand those bang-your-head-on-the-desk moments when you haven't a clue what the problem is. Over the lifetime of the app they should certainly save time overall. Any time you make a change you can run the tests quickly to check everything's working. If there is a problem the tests should tell you exactly what allowing you to fix it quickly.

One thing that does make testing hard work are poorly-designed classes. Small methods and tightly focussed classes which do just one thing are much easier to test. That's another good thing about testing: it helps to nudge you towards better designs.

Anyone looking to find out more should pop over to sitepoint.com or see some of the tutorials on http://www.lastcraft.com.

Tue, 28 Mar 2006 at 05:58:31 GMT Link


5.Ivo Jansch said:

I'm trying to introduce 'test first' in our company (as part of an attempt to put XP to practice). For some it's easy to do it, others are having difficulty with this approach, being not used to it. I have to put significant effort in teaching the testing framework and the methodology.

But most find it a very useful way of working, once they get the gist. Tests may not always drive the design (in my opinion, you do design first, then tests, finally coding), but it sure helps validating it. Also, testable code helps in keeping it reusable, by reducing (cross)dependencies. I think I can safely say: "If you are unable to test it, the design must be flawed".

Tue, 28 Mar 2006 at 06:24:34 GMT Link


6.Sebs said:

I guess the usage of mocks indicates that low couling and cohesion has been broken or neot been followed ...

I write incontainer tests a lot .. all framework components inited ;) That was a lot more effective, but needs more effort in error finding issues

Tue, 28 Mar 2006 at 08:41:39 GMT Link


7.David Rodger said:

Noel (McGruff) didn't it explicitly, but I sort of see his response as a reply to Greg's. Greg said:

>Only the simplest of designs benefits from pre-coded tests

I think that was sort of McGruff's point:

>One thing that does make testing hard work are poorly-designed classes.

>Small methods and tightly focussed classes which do just one thing are

>much easier to test.

Small, tightly-focussed classes connected and interacting can perform complex tasks.

Tue, 28 Mar 2006 at 09:23:08 GMT Link


8.Rick said:

I have been trying to start with TDD and I am wondering if anyone can point to some really good methods/practices out there. I can obviously see creating tests for various classes you base your development on, but do you then create tests for files that use those classes? It seems if not then the tests won't catch something like parameters getting swapped or something that can often happen. If you do then you've just created so many more tests to run.

The other thing is what to use for tests. I've setup a couple of test simpletest tests, but it seems with the Eclipse project and Zend working together maybe PHPUnit would be nicer to have for the integration into the IDE. (I've found myself wishing Zend Studio had this)

Tue, 28 Mar 2006 at 12:16:01 GMT Link


9.Greg Beaver said:

When I said "simplest of designs" I was referring to the task of testing something like whether the command "pear install blah" works - when you are tying together a large number of simple tasks, the interdependencies become almost impossible to test without the implementation being in place.

Testing a single class is easy. The argument that "you must be doing something wrong if testing first is more work" doesn't hold up when you look at the actual code I am talking about.

I see the most productive testing cycle as:

1) design with the intention of making it testable

2) run early simple tests of bounds without coding them (use the thing)

3) re-work to fix obvious bugs

4) re-design when unforeseen design issues arise in the implementation

5) write formal tests

#4 occasionally means scrap the design and start over, but again, I am not talking about anything as simple as a website that at most pulls together a few components, I'm talking about something like the PEAR installer that coordinates a registry, multiple configurations, command-line/web interfaces, dependency validation, downloading, web services, and so on.

Tue, 28 Mar 2006 at 14:30:36 GMT Link


10.Chris Shiflett said:

There's some very good insight from the Perl community here:

http://www.nntp.perl.org/group/perl.qa/5666

"If you write lots of code first and then try to test it, you will look and say "it's not possible to test this so I could not possibly have written my tests beforehand - those TDD guys are fools". If you write the tests beforehand (or even if you just write your code with an eye towards how it will be tested) you end up designing your systems so that even the biggest most complex pieces are testable."

Tue, 28 Mar 2006 at 16:24:37 GMT Link


11.Andrew Whitehouse said:

We don't practice TDD in my organisation so I'm doing my own research. Here's my take so far:

Writing the test first forces you to think more about the component's interface and its contract (method pre- and post-conditions) with callers. Writing the implementation first and then the test tends to make you focus on the code you've already written.

The approach described in Kent Beck's TDD by Example, is:

1. Write a test (which will break)

2. Write the implementation to make the test pass (even if it involves hard-coding values based on the knowledge of the test)

3. Refactor the code in small steps, running the unit tests after each step to ensure they still pass

So you get into the habit of starting with tests that pass, writing another test and implementation, and getting back to pass again as soon as possible (then refactor).

Assuming that you write tests before the code, and maintain the tests, you should end up with a set of unit tests that describe the current design of your code.

Tue, 28 Mar 2006 at 17:54:52 GMT Link


12.Gary Cornelisse said:

We've approached TDD a little differently or certainly in a different order. Somewhere I read the concept of Tutorial Driven Design when I was researching best practices for API design. It’s really nothing more than saying you need to write the documentation for your code first. But, more specifically, it suggests writing several examples of the API in use. We've found that our API's are much more friendly and flexible because we’re trying to imagine what the solution should look like before we solve the problem. This now gives us practical experience with the problem and solution. After we write the examples, we break them down and write positive and negative tests for each of the lines that use the soon-to-be new code. We've found that this approach helps us discover all the ways the API could be used and abused. I think one of the things people struggle with when starting to use TDD is trying to imagine all the possible tests for their code. This method has helped us get over that hurdle. And, when everything is done, you have a great start on the documentation.

Tue, 28 Mar 2006 at 21:21:11 GMT Link


13.Chris Shiflett said:

Thanks for sharing, Gary. I like the sound of your approach.

Tue, 28 Mar 2006 at 21:27:51 GMT Link


14.Michael Krenz said:

@Rick: "I've setup a couple of test simpletest tests, but it seems with the Eclipse project and Zend working together maybe PHPUnit would be nicer to have for the integration into the IDE."

Actually there is already a cool SimpleTest eclipse plugin written by Steven Balthazor. I work with Eclipse and PHPEclipse, and I use the SimpleTest plugin. It's a great timesaver. You can find the plugin on the SimpleTest SF project site.

Concerning tests, I have often found it to be beneficial to write at least some tests first. Often I couldn't come up with a clear design beforehand, because I didn't fully understand the problem domain. By writing tests, coding, refactoring, writing more tests I have often arrived at very elegant designs that I couldn't have dreamed up at the drawing board.

Wed, 29 Mar 2006 at 12:08:45 GMT Link


15.Quinton Parker said:

Personally for writing up the core classes to my php apps specially the Object-Relational classes I use simpletest to drive the design.

I find it saves hours of debugging, silly design by testing the class's public interface. This type of testing is well illustrated by Jason E. Sweat in PHP Architect's Guide To Design Patterns...

The examples make use of the well-designed simpletest framework by Marcus Baker, Harry Fuecks and other well known gurus

Go check www dot lastcraft dot com and get started with SimpleTest!

Fri, 31 Mar 2006 at 11:06:35 GMT Link


16.Chris J. said:

I just started using test-more.php, and I like it.

I never formally tested PHP before, so I want to give an example of how it's changing my code.

Let's take myAuth as an example. Before, I was doing something like this:

<?php

function myAuth()

{

$this->username = $_POST['username'];

$this->password = $_POST['password'];

}

?>

But to use test-more, I've switched to this:

<?php

function MyAuth($post)

{

$this->username = $post['username'];

$this->password = $post['password'];

}

?>

In the test file, I test different $_POST scenarios by defining $post differently. The same goes for the session array and other superglobals. This seems better to me than messing with superglobals in the test file.

What do others think? Does TDD encourage you to be more explicit in the use of superglobals, or was it wrong for me to let the tests dictate my code?

Sun, 16 Apr 2006 at 04:02:56 GMT Link


Hello! What’s your name?

Want to comment? Please connect with Twitter to join the discussion.


Work and Books

Analog Essential PHP Security HTTP Developer's Handbook