Subtest Design - Test-More/test-more GitHub Wiki

This page describes the internals of how subtests work in Test::Builder 1.5.

Overview

From a Test::Builder point of view, a subtest has to do two basic things:

  1. Set up a new test state isolated from the parent.
  2. Communicate the result of the subtest back to the parent.

This is accomplished by giving each level of testing it's own EventCoordinator and EventHandler. Communication is accomplished by handing the subtest's History object back to the parent in an event.

This design tries to keep as much of the complexity of subtests away from the EventHandler authors. Ideally all they need to worry about is "how deeply am I nested".

Creating The New Test State

In TB1, all state resided in the Test::Builder object. This made creating an isolated subtest difficult, one had to swap out the guts of the singleton with a new object and restore it later.

In TB1.5, all state resides in the EventCoordinator and EventWatchers (mostly the History object). Test::Builder no longer holds state because other builders may be generating their own events. Creating a fresh state is a matter of making a new event watchers.

The TestState is the user-visible interface to the EventCoordiantor and Watchers. It holds a stack of EventCoordinators, one for each layer of testing. It delegates all user visible methods to the EventCoordinator on top of the stack (the one representing the state of the current level of testing).

When the TestState receives a subtest_start event it will...

  • TestState fills in information about the level of nesting in the subtest_start event if it's not set. ** This prevents builders from having to track nesting, but it allows them to override if they really want to.
  • subtest_start is posted to the EventHandlers.
  • TestState creates a new EventCoordinator using the same class as the current one.
  • The current EventCoordinator gets a subtest handler from each EventHandler. ** my $subtest_handler = $handler->subtest_handler($subtest_start_event); ** The subtest event is passed in to subtest_handler so it can get information about the subtest, like how far tested it is, without having to remember this information. ** The default subtest_handler returns a new instance of the handler.
  • The subtest handlers are added to the new EventCoodinator. ** Retain the same ordering.
  • The new EventCoordinator is pushed onto the stack. ** TestState now delegates to EventCoordinator.
  • Testing continues normally from test_start to test_end.

Communicating Back

Communication back to the parent is accomplished by attaching the subtest's History object to the subtest_end event.

Once sub-testing is done, a subtest_end event will be received by TestState. When that happens...

  • TestState attaches the current History object to subtest_end.
  • TestState pops the stack of EventCoordiantors.
  • TestState asks the current EventCoordinator to post the subtest_end event.
  • Individual event handlers decide what to do with subtest_end. ** Example: the TAP formatter will issue a summarizing "ok/not ok" line.