Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

As some of you may know, I've recently been exposed to the joys of testing. What you may not know is the experiences that I have had and what has finally converted me from a supporter of testing to someone who actively enjoys it.

Recently, a client asked us to make some changes to a Web site that required me to redesign part of the database. Part of my proposal was to spend time developing a test suite to cover those areas that would be affected. I started out by write a few small tests for a security object that I create.

#!/usr/bin/perl -w use strict; use Test::More 'no_plan'; use Test::MockObject; use constant MODULE => 'XXXXXX::Security'; my $mock = Test::MockObject->new(); use_ok( MODULE ); can_ok( MODULE, 'new' ); $mock->add( cookie => sub {} ); my $sec = XXXXXX::Security->new; isa_ok( $sec, MODULE ); # testing null information my @results = $sec->validate( $mock ); ok( ! @results, 'No cookie, user, or pass should fail to validate');

That validate() method was the subject of my fourth test. As it turns out, I was getting data back when I wasn't expecting any. Oddly, this code has been running in production for well over a year with only one known bug, and this was an intermittant one that we could never track down. Since all this bug did was force people to log back in and it did not happen often enough to irritate our clients, it was given a low priority. What's worse, since I could never replicate the bug, I couldn't find it.

The fourth test that I wrote, after spending a whopping 5 minutes on this, found the bug. I was astonished. I deliberately chose the most stable module and instantly found a bug that I had never been able to track down. Hooray for testing!

As things went further, I tested the following function:

sub add_product { my ( $self, $data ) = @_; my $categoryID = $data->{categoryID}; delete $data->{categoryID}; $self->_generic_insert( $data, 'products', DONT_COMMIT ); return if $self->error; my %category = ( productID => $self->_get_identity, categoryID => $categoryID ); $self->_generic_insert( \%category, 'category_product', COMMIT ); }

The code worked perfectly and didn't require any changes. However, as I started adding to my test suite, that code started failing for no apparent reason. As it turns out, because the Web is essentially stateless and since we were running this under ISAPI, we would typically only have one method call of this type per script invocation. When trying to run sequentially run several of these types of methods, an error on a previous method call that shouldn't affect this one caused it to fail, because I had never bothered to clear the error!

We hope to eventually port this to mod_perl, but if I tried to run this code under mod_perl with persistant objects, this would have caused massive failures. Hooray for testing again!

If this wasn't enough humiliation for me (I wrote much of this code), I discovered that tests for similar functions were often significantly different in structure -- I had inconsistent APIs. Had I known about testing when I wrote this and started with "test first" methodology, this never would have happened.

I now enjoy testing. Being able to say "my tests pass", as opposed to "gosh, I think it works", is a great feeling. I'm finding bugs I never knew were there, discovering API issues that I had never known about, and when code is hard to test, I realize that I have a design problem. Pure pleasure :)


Update: Edited out an essentially duplicate closing paragraph that blyman pointed out. Thanks blyman :)

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

In reply to Further adventures with testing by Ovid

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (2)
As of 2022-08-16 05:10 GMT
Find Nodes?
    Voting Booth?

    No recent polls found