Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

comment on

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

From time to time, I remind people that they need to write tests for their work. My first real experience writing unit tests was when I uploaded CGI::Safe to the CPAN. This was actually fairly daunting due to the complex nature of some of what I was doing, coupled with the fact that I had never written tests before. Now, due to incessant prodding from chromatic, I've gone XP and have started writing unit tests before writing code.

If you've ever read anything about a new programming language, you know that you can't just read about it, you have to do it. Once you actually start getting hands-on experience, then, and only then, do you start to grok the depths (if any) of whatever you're getting into.

If you've not written tests before, the following small test script won't make much sense to you, but I'll point out the highlights that led to revelations for me.

#!/usr/bin/perl use strict; use warnings; $|++; use Test::More tests => 11; use lib ('../lib'); use Foo::Test::Engine; my $site = 'dummy'; my $engine = Foo::Test::Engine->new; ok( defined $engine, 'Engine->new should return something' ); ok( $engine->isa('Foo::Test::Engine'), 'and it should be an Engine object' ); ok( $engine->{_template}->isa('Template'), '$engine->{_template} should be a Template object' ); $engine->_process_page; ok ( ! $engine->error, '_process_page successful'.$engine->error ); my $template = $engine->_get_base_template; ok ( defined $template, 'base template is defined' ); like( $engine->headers, qr/Content-Type: text\/html/, "Headers are being created" ); # we're instantiating another engine object because the tests of priva +te # methods have already processed the output, thus creating double outp +ut my $engine2 = Foo::Test::Engine->new; my $output = $engine2->output; ok( defined $output, "Looks like we got some output" ); unlike( $output, qr/Template Not Found/, "All templates were found" ); my $output_length = length $output; my $template = $engine2->get_template; ok ($template->isa('Template'), "get_template() should return a 'Template' object"); my $test_output; $template->process( \*DATA, {}, \$test_output ) || die $template->erro +r; like( $test_output, qr/good/, '$test_output should have the word "good" in it'); is( length $output, $output_length, 'Length of $output should not chan +ge' ); __DATA__ good

Now, this is very simple. I only have 11 tests, but they are for a fairly consistent API for my Engine object. Some of my tests are dependant on the internals and I dither on whether or not that's a good thing, but the beauty of this is pretty straightforward: many of the tests handle methods that I haven't yet written. I put stubs in there that merely return some hardcoded data. Thus, I can test my API and when I need to actually write the methods, I don't have to worry about how consistent my API is. I've already figured this out.

By having a clearer idea of my API, I can better know what I need to do and I write cleaner code. A case in point was when I first started on this project in the PTE (pre-testing era), I was very proud of the fact that the core script that drives an entire site was only about 40 lines long. Now, by starting over (I wasn't very far into the project) and doing my tests up front, the problems with my previous API shone like beacons. Now, assuming that very little changes, my core script to drive an entire site can be reduced to four lines of code!

use Foo::Test::Engine; my $engine = Foo::Test::Engine->new; print $engine->headers; print $engine->output;

Further, once I find I need to rework the inner magic of my code, I am confident that I can make nice, sweeping changes and still run my tests and know instantly what went wrong. As this is a research project for my work, I've repeatedly been forced to rework things to try new ideas.

Pure bliss :) Tests. Don't leave home without 'em.


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

In reply to The Joy of Test 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 the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others chilling in the Monastery: (4)
    As of 2020-04-03 11:55 GMT
    Find Nodes?
      Voting Booth?
      The most amusing oxymoron is:

      Results (27 votes). Check out past polls.