Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I don't write test for my Perl code. But I guess, that could be a good practice somehow as it gives you more confidence. I have read some tutorial and slides on this on web and that is good enough to start small testing for my code. For example, I can take a module and figure out what each sub routine should do, pass different parameters to test workability and boundary conditions etc.

I have very large code base and written years before I joined the company. I am not asked to write test of any sort, but I think that it can add the value to the existing code and very useful for future maintainer.

How in practice the need has come for you to write the tests, and how you have taken it? (Beside CPAN testing). What are the advantages/disadvantages you have seen? What significant things you have discovered in testing process ? What tool-set you have used besides Test::More ?

Thank you monks for reading so far. I would be enlightened by your inputs. For me testing is fun and will give solidarity to Perl code overall.

Replies are listed 'Best First'.
Re: Testing Perl Code
by Corion (Patriarch) on Oct 31, 2009 at 15:43 UTC

    The best way when adding tests late in the process is in my experience to write an automated test for every new bugreport you get. That way, you automate the (soon to be tedious) retesting and prevent embarrassing regressions.

    The unfortunate thing about writing your first test is, that you will find the current internal API of the program to be unwieldly to test, as in general subroutines will be too long and will do too many things at once. For example, a subroutine will likely fall back to hardcoded defaults instead of getting them as parameters, or it will only read them from a hardcoded configuration file instead of that file being an optional parameter. Making such things optionally configurable with the resulting API remaining essentially unchanged is the interesting part that will take you a relatively long time when introducing your first tests, but I find that the safety against regressions pays off.

    And there is little more annoying for your users than them finding regressions in your application.

Re: Testing Perl Code
by Your Mother (Archbishop) on Oct 31, 2009 at 18:58 UTC

    If you have comprehensive tests, you can refactor boldly. This is liberating and makes your code less like to become a superfund site.

    Last year I wrote a bunch of SQL handling stuff under the constraint that I couldn't use my beloved DBIx::Class or any other ORM. I wrote tests as I went. Foolishly, at the end of it I discovered that the shop did have SQL::Abstract which is basically what I was rewriting but less well. I switched all the new code to SQL::Abstract inside of an hour. That was easy. The tests showed me several things I'd missed or made bad assumptions about when I refactored. Because of the tests 1) no bugs ever made it to production, 2) a refactor of two weeks worth of code took 2 hours instead of 2 more weeks.

    There are other benefits to testing. I do a lot of development on personal projects. Tests allow the quality of things I write to go from "works for me how I use it" to "works for everyone, I'd recommend it."

    I am increasingly impressed with Test::Class. Test::More is great but it provides no structure so it's easy to get spaghetti of tests. Keeping your tests easy to manage and fun to work with keeps you and your tests going. I also recommend Perl Testing: A Developer's Notebook, ISBN 9780596100926.

Re: Testing Perl Code
by dsheroh (Monsignor) on Nov 01, 2009 at 12:17 UTC
    Going into a situation like that, you basically have two options:
    1. Try to convince your boss to give you a large chunk of time to work on writing tests instead of fixing bugs or adding features. (Good luck if you try this...)
    2. The next time you go into the code to change something, first create a test script which exercises the code you're going to be changing and, as far as possible, defines how it currently behaves. Then make your changes, update the tests to match your changes, and run them again to verify that everything else still works the way it used to. (Or, if you prefer to drink the TDD kool-aid, change the tests first, run them to see them fail, and then change the code so that the tests succeed.) If you do this each time you make a change, you'll have an ever-growing test suite which will eventually cover most, if not all, of the code.
    As far as tools, I've been perfectly happy sticking with just Test::More and occasionally bringing in Test::Warn or Test::Exception where needed.
Re: Testing Perl Code
by pemungkah (Priest) on Nov 03, 2009 at 06:23 UTC
    "When eating an elephant, take one bite at a time."

    Another approach is simply to commit yourself to adding (at least) one test a day to the test suite. Picking the low-hanging fruit is perfectly acceptable - does the module load without error? Do I have all the methods I expected to have? If the module exports symbols, do I have them? If the Pod says this call dies, does it?

    You can actually add a lot of value with tests like these (e.g.: someone accidentally leaves out a =cut, thereby commenting out a swath of methods - the "do I have all my methods" test will catch this. Syntax errors in the code? The "does my module load" test catches those before you commit to the repository.

    As mentioned, adding a test for each new bug (illustrate the wrong behavior happens/the right behavior doesn't, then test for the right answer), add a test for each change you make (the code should now do this) will all help build a test suite dynamically.

    Feel free to put in TODO tests that simply fail for the moment:

    TODO: { local $TODO = "Test not yet implemented"; fail "Missing a test for X"; }
    This will "pass" as a TODO test and remind you that you wanted to test feature X later. You can then go back and add a failing test for X; when you finally fix (or implement) X, you'll get an UNEXPECTEDLY SUCCEEDED and can go back and remove the TODO wrapper from the test.

    Anything you run to check your code, or see a peer run, is a potential test. Just look for a way for a program to automate it -WWW::Mechanize for web checks, Expect for command-line programs, and so on.

    You are absolutely right: testing will make your life easier. If you need to justify developing tests, keep a log of the amount of time you spend writing tests, and then for each test, keep a count of how many times that test finds an error for you. You may be surprised (and your peers/management may be very surprised) how quickly those add up!

    Remember: a little testing is better than no testing at all.