Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number

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":

  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?

    What's my password?
    Create A New User
    and all is quiet...

    How do I use this? | Other CB clients
    Other Users?
    Others exploiting the Monastery: (4)
    As of 2018-04-23 16:38 GMT
    Find Nodes?
      Voting Booth?