NAME
Test::Future::IO
- unit testing on Future::IO
SYNOPSIS
use Test::More;
use Test::Future::IO;
my $controller = Test::Future::IO->controller;
{
$controller->expect_syswrite_anyfh( "Hello, world\n" );
$controller->expect_sysread_anyfh( 256 )
->will_done( "A string\n" );
code_under_test();
$controller->check_and_clear( 'code under test did correct IO' );
}
DESCRIPTION
This package provides a means to apply unit testing around code which uses Future::IO. It operates in an "expect-and-check" style of mocking, requiring the test script to declare upfront what methods are expected to be called, and what values they return.
EXPECTATIONS
Each of the actual Future::IO
methods has a corresponding expectation method on the controller object, whose name is prefixed with expect_
. A single call to one of these methods by the unit test script represents a single call to a Future::IO
method that the code under test is expected to make. The arguments to the expectation method should match those given by the code under test. Each expectation method returns an object which has additional methods to control the behaviour of that invocation.
$exp = $controller->expect_accept( $fh );
$exp = $controller->expect_connect( $fh, $name );
$exp = $controller->expect_sleep( $secs );
$exp = $controller->expect_sysread( $fh, $len );
$exp = $controller->expect_syswrite( $fh, $bytes );
For testing simpler code that does not operate on multiple filehandles, two additional methods that ignore the filehandle argument may be more convenient:
$exp = $controller->expect_sysread_anyfh( $len );
$exp = $controller->expect_syswrite_anyfh( $bytes );
In each case the returned expectation object allows the test script to specify what such an invocation should return.
$exp->will_done( @result );
Expectations can make methods fail instead.
$exp->will_fail( $message );
$exp->will_fail( $message, $category, @details );
Expectations can be set to remain pending rather than completing.
$exp->remains_pending;
As a convenience, a syswrite
expectation will default to returning a future that will complete yielding its length (as is usual for successful writes), and a sleep
or connect
expectation will return a future that completes yielding nothing.
Testing event-based code with expect_sysread
can be fragile, as it relies on exact ordering, buffer sizes, and so on. A more flexible approach that leads to less brittle tests is to use a buffer around that filehandle that is provided by the test module. The test module then intercepts all sysread
method calls on the given filehandle to return data from that buffer:
$controller->use_sysread_buffer( $fh );
$controller->write_sysread_buffer( $fh, $data );
As a convenience for filling the sysread buffer at the right time, any expectation returned by this module supports two extra methods for invoking write_sysread_buffer
when another expectation completes:
$exp->will_write_sysread_buffer( $fh, $data );
$exp->will_write_sysread_buffer_later( $fh, $data );
These are both shortcuts for calling "write_sysread_buffer" from within a will_also
or will_also_later
code block.
METHODS
controller
$controller = Test::Future::IO->controller;
Returns the control object, on which the various expect_*
methods and check_and_clear
can be invoked.
check_and_clear
$controller->check_and_clear( $name );
Checks that by now, every expected method has been called, and emits a new test output line via Test::Builder. Regardless, the expectations are also cleared out ready for the start of the next test.
use_sysread_buffer
$controller->use_sysread_buffer( $fh );
Since version 0.05.
This method enables a read buffer for a given filehandle, that provides an alternative means of testing reading on a filehandle than using expect_sysread
. Once enabled, Future::IO->sysread
calls on the given filehandle handled internally by the test controller.
The sysread buffer is initially empty, and can be written to by "write_sysread_buffer".
This is provided using a Test::ExpectAndCheck::Future
->whenever
expectation, which is returned by this method. This is useful in case you want to call the ->indefinitely
method on it, meaning it will survive past calls to "check_and_clear".
$controller->use_sysread_buffer( "FH" )
->indefinitely;
write_sysread_buffer
$controller->write_sysread_buffer( $fh, $data );
Since version 0.05.
Appends more data to the sysread buffer previously established by the "use_sysread_buffer".
Typically this is performed either initially as part of test setup, or later as a side-effect of other expectations completing.
For example:
$controller->use_sysread_buffer( "FH" );
$controller->expect_syswrite( "FH", "Question?\n" )
->will_write_sysread_buffer_later( "FH", "Answer!\n" );
TODO
Provision of a mock filehandle object to assist unit tests.
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>