Michael Granger

NAME

Test::SimpleUnit - Simplified Perl unit-testing framework

SYNOPSIS

  use Test::SimpleUnit qw{:functions};
  runTests(
    {name => "test1", test => sub {...}},
    {name => "testN", test => sub {...}}
  );

EXAMPLE

  use Test::SimpleUnit qw{:functions};
  
  # If a setup or teardown function fails, skip the rest of the tests
  Test::SimpleUnit::AutoskipFailedSetup( 1 );
  Test::SimpleUnit::AutoskipFailedTeardown( 1 );
  
  my $Instance;
  my $RequireWasOkay = 0;
  
  my @tests = (
    
    # Require the module
    {
      name => 'require',
      test => sub {
        
        # Make sure we can load the module to be tested.
        assertNoException { require MyClass };
        
        # Try to import some functions, generating a custom error message if it
        # fails.
        assertNoException { MyClass->import(':myfuncs') } "Failed to import :myfuncs";
        
        # Make sure calling 'import()' actually imported the functions
        assertRef 'CODE', *::myfunc{CODE};
        assertRef 'CODE', *::myotherfunc{CODE};
        
        # Set the flag to let the setup function know the module loaded okay
        $RequireWasOkay = 1;
      },
    },
    
    # Setup function (this will be run before any tests which follow)
    {
      name => 'setup',
      test => sub {
        # If the previous test didn't finish, it's untestable, so just skip the
        # rest of the tests
        skipAll "Module failed to load" unless $RequireWasOkay;
        $Instance = new MyClass;
      },
    },
    
    # Teardown function (this will be run after any tests which follow)
    {
      name => 'teardown',
      test => sub {
        undef $Instance;
      },
    },
    
    # Test the connect() and disconnect() methods
    {
      name => 'connect() and disconnect()',
      test => sub {
          my $rval;
          
          assertNoException { $rval = $Instance->connect };
          assert $rval, "Connect failed without error.";
          assertNoException { $Instance->disconnect };
      },
    },
    
    # One-time setup function -- overrides the previous setup, but is
    # immediately discarded after executing once.
    {
      name => 'setup',
      func => sub {
          MyClass::prepNetwork();
      },
    },
    
    # Now override the previous setup function with a new one that does
    # a connect() before each remaining test.
    {
      name => 'setup',
      test => sub {
          $Instance = new MyClass;
          $Instance->connect;
      },
    }
    
    # Same thing for teardown/disconnect()
    {
      name => 'teardown',
      test => sub {
        $Instance->disconnect;
        undef $Instance;
      },
    },
    
    ...
    
  );
  
  runTests( @testSuite );

DESCRIPTION

This is a simplified Perl unit-testing framework for creating unit tests to be run either standalone or under Test::Harness.

Testing

Testing in Test::SimpleUnit is done by running a test suite, either via 'make test', which uses the Test::Harness 'test' target written by ExtUtils::MakeMaker, or as a standalone script.

If errors occur while running tests via the 'make test' method, you can get more verbose output about the test run by adding TEST_VERBOSE=1 to the end of the make invocation:

  $ make test TEST_VERBOSE=1

If you want to display only the messages caused by failing assertions, you can add a VERBOSE=1 to the end of the make invocation instead:

  $ make test VERBOSE=1

Test Suites

A test suite is one or more test cases, each of which tests a specific unit of functionality.

Test Cases

A test case is a unit of testing which consists of one or more tests, combined with setup and teardown functions that make the necessary preparations for testing.

You may wish to split test cases up into separate files under a t/ directory so they will run under a Test::Harness-style make test.

Tests

A test is a hashref which contains two key-value pairs: a name key with the name of the test as the value, and a code reference under a test key:

  {
    name => 'This is the name of the test',
    test => sub { ...testing code... }
  }

Each test's test function can make one or more assertions by using the Assertion Functions provided, or can indicate that it or any trailing tests in the same test case should be skipped by calling one of the provided Skip Functions.

Setup and Teardown Functions

If a test has the name 'setup' or 'teardown', it is run before or after each test that follows it, respectively. A second or succeeding setup or teardown function will supersede any function of the same type which preceded it. This allows a test designer to change the setup function as the tests progress. See the EXAMPLE section for an example of how to use this.

If a test is preceeded by multiple new setup/teardown functions, the last one to be specified is kept, and any others are discarded after being executed once. This allows one to specify one-time setup and/or teardown functions at a given point of testing.

The code reference value within a setup or teardown test case can optionally be named func instead of test for clarity. If there are both func and test key-value pairs in a setup or teardown case, the test pair is silently ignored.

Saving Test Data

If the test suite requires configuration, or some other data which should persist between test cases, it can be dumped via Data::Dumper to a file with the saveTestData() function. In succeeding tests, it can be reloaded using the loadTestData() function.

REQUIRES

Carp, Data::Compare, Data::Dumper, Exporter, Fcntl, IO::File, IO::Handle, Scalar::Util

EXPORTS

Nothing by default.

This module exports several useful assertion functions for the following tags:

:asserts

assert, assertNot, assertDefined, assertUndef, assertNoException, assertException, assertExceptionType, assertExceptionMatches, assertEquals, assertMatches, assertRef, assertNotRef, assertInstanceOf, assertKindOf, fail

:skips

skipOne, skipAll

:testFunctions

runTests

:testdata

loadTestData, saveTestData

:functions

All of the above.

AUTHOR

Michael Granger <ged@FaerieMUD.org>

Copyright (c) 1999-2003 The FaerieMUD Consortium. All rights reserved.

This module is free software. You may use, modify, and/or redistribute this software under the terms of the Perl Artistic License. (See http://language.perl.com/misc/Artistic.html)

FUNCTIONS

AutoskipFailedDataLoad( $trueOrFalse )

If set to a true value, any failure to reload test data via loadTestData() will cause the test to be skipped instead of running.

AutoskipFailedSetup( $trueOrFalse )

If set to a true value, any failed setup functions will cause the test to be skipped instead of running.

AutoskipFailedTeardown( $trueOrFalse )

If set to a true value, any failed teardown functions will cause the test to be skipped instead of running.

Debug( $trueOrFalse )

If set to a true value, the test suite will be dumped to STDERR before running.

OutputHandle( $handle )

Set the handle that will be used to output test progress information. This can be used to run tests under Test::Harness without influencing the test result, such as when invoking runTests() from within an assertion. It defaults to STDOUT, which will be what it is restored to if it is called with no argument. The argument is tested for support for the 'print', 'flush', and 'printf' methods, and dies if it does not support them. This function is mostly to support self-testing.

runTests( @testSuite )

Run the tests in the specified testSuite, generating output appropriate for the harness under which it is running. The testSuite should consist of one or more hashrefs of the following form:

Assertion Functions

assert( $value[, $failureMessage] )

Die with a failure message if the specified value is not true. If the optional failureMessage is not given, one will be generated.

assertDefined( $value[, $failureMessage] )

Die with a failure message if the specified value is undefined. If the optional failureMessage is not given, one will be generated.

assertEquals( $wanted, $tested[, $failureMessage] )

Die with a failure message if the specified wanted value doesn't equal the specified tested value. The comparison is done with Data::Compare, so arbitrarily complex data structures may be compared, as long as they contain no GLOB, CODE, or REF references. If the optional failureMessage is not given, one will be generated.

assertException( \&code[, $failureMessage] )

Evaluate the specified coderef, and die with a failure message if it does not generate an exception. If the optional failureMessage is not given, one will be generated.

assertExceptionMatches( \&code, $regex[, $failureMessage] )

Evaluate the specified coderef, and die with a failure message if it does not generate an exception which matches the specified regex. If the optional failureMessage is not given, one will be generated.

assertExceptionType( \&code, $type[, $failureMessage] )

Evaluate the specified coderef, and die with a failure message if it does not generate an exception which is an object blessed into the specified type or one of its subclasses (ie., the exception must return true to $exception-isa($type)>. If the optional failureMessage is not given, one will be generated.

assertInstanceOf( $wantedClass, $testedValue[, $failureMessage] )

Die with a failure message if the specified testedValue is not an instance of the specified wantedClass. If the optional failureMessage is not given, one will be generated.

assertKindOf( $wantedClass, $testedValue[, $failureMessage] )

Die with a failure message if the specified testedValue is not an instance of the specified wantedClass or one of its derivatives. If the optional failureMessage is not given, one will be generated.

assertMatches( $wantedRegexp, $testedValue[, $failureMessage] )

Die with a failure message if the specified tested value doesn't match the specified wanted regular expression. If the optional failureMessage is not given, one will be generated.

assertNoException( \&code[, $failureMessage] )

Evaluate the specified coderef, and die with a failure message if it generates an exception. If the optional failureMessage is not given, one will be generated.

assertNot( $value[, $failureMessage] )

Die with a failure message if the specified value is true. If the optional failureMessage is not given, one will be generated.

assertNotRef( $testedValue[, $failureMessage] )

Die with a failure message if the specified testedValue is a reference of any kind. If the optional failureMessage is not given, one will be generated.

assertRef( $wantedType, $testedValue[, $failureMessage] )

Die with a failure message if the specified testedValue is not of the specified wantedType. The wantedType can either be a ref-type like 'ARRAY' or 'GLOB' or a package name for testing object classes. If the optional failureMessage is not given, one will be generated.

assertUndef( $value[, $failureMessage] )

Die with a failure message if the specified value is defined. If the optional failureMessage is not given, one will be generated.

fail( [$failureMessage] )

Die with a failure message unconditionally. If the optional failureMessage is not given, a generic failure message will be used instead.

Private Functions

_CountAssertion()

Add 1 to the count of assertions run in the current counter frame.

_CountSuccess()

Add 1 to the count of successful assertions in the current counter frame.

_PopAssertionCounter()

Remove the current assertion counter, and return a list of the number of assertions run, and the number of assertions which succeeded.

_PushAssertionCounter()

Add a pair of assertion counters to the stack. Assertion counters are used to count assertion runs/successes, and this adds a level in case of recursive runTests() calls.

Protected Functions

_prepSuite( @tests )

Split the specified array of test hashrefs into three arrays: setupFuncs, tests, and teardownFuncs. Return references to the three arrays.

_runTests( \@setupFuncs, \@tests, \@teardownFuncs )

Run the specified tests, running any setupFuncs before each one, and any teardownFuncs after each one.

Skip Functions

skipAll( [$message] )

Skip all the remaining tests, optionally outputting a message as to why the they were skipped.

skipOne( [$message] )

Skip the rest of this test, optionally outputting a message as to why the rest of the test was skipped.

Test Data Functions

loadTestData( $filename )

Load key/data pairs from a data file that was saved from previous tests. Returns a reference to a hash of data items.

saveTestData( $filename, %datahash )

Save the key/value pairs in %datahash to a file with the specified filename for later loading via loadTestData().