# You may distribute under the terms of either the GNU General Public License # or the Artistic License (the same terms as Perl itself) # # (C) Paul Evans, 2020 -- leonerd@leonerd.org.uk package Test::ExpectAndCheck::Future; use strict; use warnings; use base qw( Test::ExpectAndCheck ); our $VERSION = '0.02'; use constant EXPECTATION_CLASS => "Test::ExpectAndCheck::Future::_Expectation"; =head1 NAME C - C-style unit testing with C-returning methods =head1 SYNOPSIS use Test::More; use Test::ExpectAndCheck::Future; my ( $controller, $puppet ) = Test::ExpectAndCheck::Future->create; { $controller->expect( act => 123, 45 ) ->returns( 678 ); is( $puppet->act( 123, 45 )->get, 678, '$puppet->act yields result' ); $controller->check_and_clear( '->act' ); } done_testing; =head1 DESCRIPTION This package creates objects that assist in writing unit tests with mocked object instances. Each mocked "puppet" instance will expect to receive a given list of method calls. Each method call is checked that it received the right arguments, and will return a L instance to yield the prescribed result. At the end of each test, each object is checked to ensure all the expected methods were called. It is a variation of L, assistance around the results of invoked methods. Every invoked method will return a L instance. The L or L method can then set the desired eventual result of that future instance for each expectation. These return instances are implemented using L, so they are not immediately ready. Instead they will only become ready after a toplevel C expression or call to the C method. This should help unit tests to run similarly to real-world behaviour, where most futures returned by real-world interfaces (such as IO systems) would not be immediately ready. This behaviour can be switched off for individual expectations by using the L method. =cut package Test::ExpectAndCheck::Future::_Expectation; use base qw( Test::ExpectAndCheck::_Expectation ); use Test::Future::Deferred; use constant { RETURNS => 3, FAILURE => 6, IMMEDIATE => 7, }; =head1 EXPECTATIONS =head2 returns $exp->returns( @result ) Sets the result that the future returned by this method call will yield. =cut =head2 fails $exp->fails( $message ) $exp->fails( $message, $category, @details ) Sets the failure that the future returned by this method call will yield. =cut sub fails { my $self = shift; $self->[FAILURE] = [ @_ ]; return $self; } =head2 immediately $exp->returns( ... )->immediately $exp->fails( ... )->immediately Switches this expectation to return an immediate future, rather than a deferred one. =cut sub immediately { my $self = shift; $self->[IMMEDIATE]++; } sub _result { my $self = shift; if( $self->[IMMEDIATE] ) { return Future->fail( @{ $self->[FAILURE] } ) if $self->[FAILURE]; return Future->done( @{ $self->[RETURNS] } ); } else { return Test::Future::Deferred->fail_later( @{ $self->[FAILURE] } ) if $self->[FAILURE]; return Test::Future::Deferred->done_later( @{ $self->[RETURNS] } ); } } =head1 AUTHOR Paul Evans =cut 0x55AA;