-
Notifications
You must be signed in to change notification settings - Fork 0
pawjy/perl-test-x1
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
=head1 NAME Test::X1 - A lightweight test manager =head1 SYNOPSIS use Test::X1; use Test::More; test { my $c = shift; ok 1; ok 2; $c->done; }; test { my $c = shift; my $timer; $timer = AnyEvent->timer( after => 2, cb => sub { test { ok 2; is 3, 0; undef $timer; $c->done; undef $c; } $c; }, ); ok 1; } n => 3, name => ['anyevent', 'callback']; test { my $c = shift; ok 1; $c->done; } n => 1; run_tests; ok 1 - [1] - [1] ok 2 - [1] - [2] ok 3 - [2] anyevent.callback - [1] ok 4 - [3] - [1] ok 5 - [2] anyevent.callback - [2] not ok 6 - [2] anyevent.callback - [3] # Failed test '[2] anyevent.callback - [3]' # at lib/Test/X1.pod line 24. # got: '3' # expected: '0' # [2] anyevent.callback: 1 test failed 1..6 # Looks like you failed 1 test of 6. =head1 DESCRIPTION The C<Test::X1> module defines a simple, lightweight, and L<AnyEvent>-compatible test management framework for L<Test::Builder>-based tests. It supports automatic naming of tests, partial execution, concurrent execution, and other useful features. =head1 USAGE By C<use>ing the C<Test::X1> module, functions for defining and running tests are exported to the caller package. Note that it only exports test management functions. You have to import or define your favorite test assertion sets such as L<Test::More> or L<Test::Differences> by yourself. The C<Test::X1> test framework only assumes that you are writing a L<Test::Builder>-based test script. As long as test assertion functions are build upon L<Test::Builder>'s framework, you can choose any test module. Note that some test modules are incompatible with L<AnyEvent>-based asynchronous invocation of callbacks. For example, C<subtest>s of L<Test::More> does not work well. =head2 Tests A C<Test::X1>-based test script consists of one or more tests. A I<test> is a group of I<subtests>, which are L<Test::Builder>-based assertion functions such as I<is> and I<ok>. A test can be defined by enclosing subtests and related codes by the C<test{}> function: test { my $c = shift; is 2 * 4, 8; is 40 - 30, 10; $c->done; }; This usage of the C<test{}> function is sometimes referred to as I<test definition>. The code block in the test definition is invoked with an argument, the context object for the test, I<$c>. The C<< $c->done >> method has to be called when all subtests in the test are done. (See L</"Context objects"> for more information on I<$c>.) You can specify the number of subtests in a test by specifying the C<n> option to the test definition. If the C<n> option is specified, it is verified that the expected number of subtests are done before the C<< $c->done >> metohd is invoked. It is considered as good practice to specify the number of subtests, especially when there are loops in the test, such that it can be confirmed that all expected subtests are really executed. Since the number of subtests can be frequently changed in some cases, or it could even be unknown a priori, the C<n> option is not required. The test can be named by specifying the C<name> option to the test definition. The name of the test is C<[n]>, where I<n> is the sequential number of the test, followed by space and C<name> value if any, e.g. C<[1] hoge> or C<[2]>. The name of the test is used to construct the name of the subtests in the test. The C<TEST_METHOD> environment variable can be used to specify the regular expression used to filter the tests to run by their names. If the environment variable is not set, all tests are executed. Otherwise, only the tests whose name matches the pattern are executed. The C<TEST_METHOD_EXCLUDED> environment variable can be used to specify the regular expression used to filter the tests to I<not> run by their names. If the environment variable is not set, no test is excluded. See also L</Naming> for how names are handled and used by the module. For example, consider the following test script: # t/foo.t use Test::X1; use Test::More; my $x = 10; test { my $c = shift; is $x, 10; $c->done; } name => 'abc2'; test { my $c = shift; is $x * 2, 20; $c->done; }; run_tests; The first test is named as C<[1] abc2>, while the second test is named as C<[2]>. If the script is executed with no C<TEST_METHOD>, both of them are executed. If the script is executed with C<TEST_METHOD=abc>, only the first test is executed. If the script is executed with C<TEST_METHOD=2>, both of them are executed. The C<run_tests> function runs the tests defined by C<test{}> functions. It must be invoked exactly once in the test script, after all tests are defined. You can run any preparation code before the invocation, or cleanup code after the invocation. The C<run_tests> function does not return until all tests are done. =head2 Context objects The code block in the test definition is invoked with an argument, i.e. the context object, in the C<@_> array. The context object provides several utility methods for the test and is created specifically for the test. In other word, different context objects are created for different test definitions. In this document, the context object is sometimes referred to as C<$c>. The most significant method of the test context object is the C<done> method. The C<< $c->done >> method must be invoked when and only when all the subtests in the test has been done, successfully or not. Once the method has been invoked, no subtest can be performed in the test. If the method is not invoked in the test, an error would be reported. The most basic usage would be invoking the C<< $c->done >> method just before the end of the test code: test { my $c = shift; ... tests ... $c->done; }; If there are callbacks, the C<< $c->done >> method should be invoked at the end of the last callback (the one invoked finally): test { my $c = shift; my $timer = AE::timer 10, 0, sub { test { ...; $c->done; undef $c; } $c; }; }; The inner C<test{}> statement is a test block; See L</"Test blocks"> for details. Also note that C<undef $c> is executed after C<< $c->done >> is invoked. Though this is not required for this particular case, it might be a good practice to C<undef> the context object reference when it is C<done>'ed within a callback function as it would delete a possible loop reference when the context object has the reference to some object and the object then contains the reference to the callback function which contains the reference to the context object. More complex example: test { my $c = shift; my $cv = AE::cv; # This callback will be executed after all of # following callbacks are invoked. $cv->begin (sub { test { $c->done } $c }); $cv->begin; my $timer1 = AE::timer 10, 0, sub { $cv->end }; $cv->begin; my $timer2 = AE::timer 4, 0, sub { $cv->end }; ... $cv->end; }; Application test framework built on top of the module might define additional methods to context objects. See L</"Subclassing"> on the guideline for extending the context object interface. =head2 Test blocks Another usage of the C<test{}> function is defining a B<test block>. They are different from the test definitions in that they are used within some test definition and takes the test context object I<$c> as the first argument. Test blocks are typically used within callback functions in a test; in fact there has to be a test block within an asynchronously invoked callback function: test { my $c = shift; AE::io *STDIN, 0, sub { test { is scalar <STDIN>, "hoge"; $c->done; } $c; }; }; A test block gives the test context as encapsulated by I<$c> to the subtests within the block. You have to enclose subtests within callback functions by yourself, unfortunately, otherwise the test manager losts the association of subtests and their "parent" test, due to the asynchronousness of the invocation of the callback. Test block can be named by the C<name> option: test { test { ok 1, 'Test X'; } $c, name => 'hoge'; }; # ok 1 - [1] - [1] hoge Test X The C<TEST_BLOCK_SKIP> environment variable can be used to specify the regular expression to skip the test blocks with names matching to the pattern. For example, C<TEST_BLOCK_SKIP=og.$> would prevent the C<ok> statement in the example above from executed. See also L</Naming>. =head2 Naming Tests, test blocks, and subtests can be named. Instead of a scalar value, representing the literal string, an array reference containing string components can be specified. test { my $c = shift; test { is $hoge, $fuga, 'Subtest 1'; } $c, name => 'Test block 1'; $c->done; } name => 'Test 1'; test { my $c = shift; test { is $hoge, $fuga, ['Subtest', 2]; } $c, name => ['Test block', 2]; $c->done; } name => ['Test', 2]; Naming by array reference would be particularly useful when defining multiple tests by iteration: for my $value (1, 2, 30, 120) { test { my $c = shift; like $c, qr{^\d+$}; $c->done; } name => ['Test', $value]; } If the name is represented as an array reference, its items are joined by C<.> (period) before actually used to output results, or filter tests by environment variables, i.e. C<TEST_METHOD>, C<TEST_METHOD_EXCLUDED>, and C<TEST_BLOCK_SKIP>. Any empty string is replaced by C<(empty)> and any C<undef> value is replaced by C<(undef)>. =head2 Waiting for a condvar An L<AnyEvent> condvar can be specified as the C<wait> parameter to a test definition (I<not> test block!) to wait for the condvar to receive a value. The received value can be accessed from the C<< $c->received_data >> method of the context object. my $cv = AE::cv; test { my $c = shift; is $c->received_data, 123; $c->done; } wait => $cv; Instead of a codevar object, a code reference which, when invoked, returns a condvar object or the C<undef> value can be specified as the C<wait> value. This practice is rather recommended as it would prevend the condvar object from being instantiated when the target tests are filtered by C<TEST_METHOD> environment variable. For example, test { my $c = shift; is $c->received_data, 123; $c->done; } wait => sub { start_server_and_return_cv () }; ... does not start the server for the test when the test is excluded from the execution. The default C<wait> value, used when no C<wait> parameter is explicitly specified to test definitions, can be provided by subclassing (see L</"Subclassing"> for details) and defining C<< $tm->default_test_wait_cv >> method returning a condvar (or C<undef>) in the test manager subclass. In this case, by explicitly setting C<undef> value for the C<wait> parameter of test definitions, this default can be cleared. (See C<t/cv-wait-default.t> test script for examples.) The C<wait> value can also be a hash reference (or a code reference which returns a hash reference). The C<cv> key of the hash reference can have the condvar object as the value. The C<destroy_as_cv> key can contain the code reference, which will be invoked after relevant tests have been run. The code should be useful to stop the server started by the C<cv> condvar's preparation, for example. The code must return a condvar object, whose callback will be invoked after the destroy process has been done. The same C<destroy_as_cv> code is invoked only once. If the code is specified as part of the C<wait> value of multiple tests, it is only invoked after all of them has been executed. Example: test { ... } wait => {cv => sub { return $server->start_as_cv; }, destroy_as_cv => sub { return $server->stop_as_cv; }}; Additionally, the C<timeout> value can also be specified in the C<wait> hash reference. Its default value is 60. After the seconds of the timeout elapse, if the C<wait> condvar's callback is not invoked, the associated test fails. The timeout value is also applied to the C<context_begin> and C<context_end> methods of the C<< $c->received_data >> object; These methods have to invoke the callback before the timeout. Please note that they should not block the entire script, otherwise the timeout will not work. =head2 Concurrent execution of tests Thanks to L<AnyEvent> framework, tests (as defined by outermost C<test{}> functions) can be concurrenrly executed when they are written in non-blocking way using L<AnyEvent>. Consider the following test script fragment: test { my $c = shift; ok 'Subtest #1.1'; AnyEvent::Example->something(cb => sub { test { is $_[0], 'hoge', 'Subtest #1.2'; $c->done; } $c; }); }; test { my $c = shift; ok 'Subtest #2.1'; AnyEvent::Example->something(cb => sub { test { is $_[0], 'hoge', 'Subtest #2.2'; $c->done; undef $c; } $c; }); }; run_tests; In this case, execution order of Subtests #1.2 and #2.2 is unclear at all, depending on how long C<< AnyEvent::Example->something >> defers the execution of the callbacks. (Please also note that, although in the current implementation Subtest #2.1 is always executed after Subtest #1.1, as that test is defined by C<test{}> after the other test, this is not guaranteed and you should not reply on this exact order. Future version of the module could introduce shuffling execution mode, for instance.) Anyway, we can describe this situation that multiple tests are concurrently executed. By default, at most five tests are concurrently executed by C<Test::X1>. Setting a number to the C<TEST_MAX_CONCUR> environment variable can override this default, if desired. C<TEST_MAX_CONCUR=1> disables this concurrency, which will be useful for debugging purposes in particular. =head2 More test option The C<timeout> option of the test definition (not a test block) specifies the timeout in seconds. The test must end within the seconds after the test is started (not inlcuding any C<wait>, C<context_before>, and C<context_after> processing). The default value is 60. Note that the timeout might be applied as intended if the test blocks the script, by, e.g., blocking I/O access, C<system>, or C<sleep>. =head2 Subclassing Test scripts often need application-specific factory functions and/or utility functions to create expected precondition or to manage states of tested environment. For example, a test for Web application would need to start a Web server before any test and stop the server after tests. A test for database operation would want to insert a number of records into the database at some points in the test code. Although they can be implemented orthogonally from the C<Test::X1>'s framework, subclassing of the L<Test::X1> class should be a good candidate if you want to control the lifetime of such temporary objects by relating them with lexical scopes of tests. If you'd like to extend C<Test::X1> for your application C<My>, the subclass module, C<My/Test/X1.pm>, would look like: package My::Test::X1; use Test::X1 (); Test::X1::define_functions(__PACKAGE__); package My::Test::X1::Manager; sub my_create_database { ... } sub my_drop_database { ... } sub stop_test_manager { shift->my_drop_database } package My::Test::X1::Context; sub my_insert_data { ... } 1; The C<Test::X1> module is C<use>d without importing any function, then the C<Test::X1::define_functions> function is invoked with the package, i.e. C<My::Test::X1>. Additional methods are defined in subclasses of test manager and context objects. Then, in your test script, instead of directly C<use>ing C<Test::X1> module, load your module: use My::Test::X1; my $tm = get_test_manager; $tm->my_create_database; test { my $c = shift; $c->my_insert_data; ... }; run_tests; It is considered as good practice to prepend a short prefix taken from the subclass name (C<my_> in this example) to the method names defined by subclasses such that future additions to base classes will not conflict with them. Both test manager and context objects are blessed hash references. Subclasses can use hashes to save their data associated with objects. Such hash keys should be prefixed by subclass names as well. =head1 EXPORTED FUNCTIONS By C<use>ing the C<Test::X1> module, your test script imports following functions: =over 4 =item $tm = get_test_manager Obtain the instance of the test manager for the test script. The test manager object is singleton; the function always returns the same object. =item test { CODE } NAME => VALUE, ...; (Test definition) Define a test. It must be invoked outside of any other C<test{}> function call. It must be invoked before C<run_tests> function call. The code block is expected to run one or more subtests. The number of subtests is expected to be equal to the C<n> parameter value, if specified. The code is expected to not throw any exception. The code block, when invoked, receives the text context object I<$c> for the test as the argument. The C<< $c->done >> method is expected to be invoked after all subtests are run. See also L</Tests> for usage. After the code block, zero or more name/value pairs can be specified. Following name/value pairs are supported: =over 4 =item n => non-negative integer Specify the expected number of substests in the test. If the parameter is not specified, number of subtests are not known a priori. =item name => string or array reference of strings Name the test. See L</Naming> for details. =item wait => anyevent-condvar Specify a L<AnyEvent::CondVar> object to wait before the execution of the test. See also L</"Waiting for a condvar">. =back =item test { CODE } $c, NAME => VALUE, ...; (Test block) Define a subpart of test (or a block of subtests). It must be invoked within the code part of a test definition. See also L</"Test blocks">. The context object for the current test must be specified as the argument next to the code block. Additionally, zero or more name/value pairs can be specified. =over 4 =item name => string or array reference of strings Name the test block. See L</Naming> for details. =back =item run_tests Run the defined tests. The function returns after all the tests has been executed and done. This function must be invoked exactly once in the test script. After the function call, the C<test{}> function (for defining a test) must not be invoked. =back =head1 TEST MANAGER OBJECT The test manager object is the object created for the test script, holding references to tests in the test script and monitoring their results. The test manager object is singleton; there is at most one test manager object at one time. The C<Text::X1> class (and its subclasses) exports C<get_test_manager> function, which takes no argument, returning the current test manager object. If you are writing simple test scripts, you don't have to directly access test manager usually. The exported functions explained in the previous section are in fact invoking appropriate methods of the test manager object. Following methods can be invoked or defined when you are subclassing the test manager object: =over 4 =item $cv = $tm->default_test_wait_cv This method can be overridden by subclasses, if desired. This method is expected to return an L<AnyEvent> condvar or C<undef>. The value returned by this method is used as the C<wait> parameter value of test definitions, when it is not explicitly specified. =item $hashref = $tm->context_args This method can be overridden by subclasses, if desired. This method is invoked when test context objects are created. It is expected to return a hash reference containing name/value pairs passed as arguments to the C<new> method of the test context class. By default it returns an empty hash reference. Name/value pairs specified here can be accessed from the test context object's blessed hash reference. See L</"Subclassing"> for their usage. =item $tm->stop_test_manager This method can be overridden by subclasses, if desired. This method is invoked before the test manager object is destructed. It is expected to be used to close anything opened by the test manager, if necessary. This method can be invoked more than once for an test manager object. The C<Test::X1> module does it's best effort to invoke the method for the test manager object before Perl goes into the global destruction phase. =item $tm->diag($color, $message) =item $tm->note($color, $message) Print a diagnostic message or a note, through C<Test::Builder>'s C<diag> or C<note> method. For their usage, see L<Test::Builder> and L<Test::More> documentations. The first argument must be a color specification for L<Term::ANSIColor>, e.g. C<"red"> or C<"">. The second argument must be a diagnostic or note text, possibly utf8-flagged. =back =head1 CONTEXT OBJECT The context object is created for each test. It provides several information on the test, which can be used within test for debugging purpose. The context object is passed to the test as the first argument. =over 4 =item $name = $c->test_name The compound name of the test, in a single character string. However the name is specified (or not), the method returns the single string as used in TAP test name part. See L</Naming>. =item $data = $c->received_data Return the data received from the L<AnyEvent> condvar specified to the C<wait> parameter of the test definition for the current test. See also L</"Waiting for a condvar">. The data can be any value, including the C<undef> value. If the data is an object which has C<context_begin> and C<context_end> methods, they are invoked just after and just before the data is associated with a context object. (Please note that the data can be associated with multiple context objects when the condvar is specified for multiple tests.) Both methods will receive a code reference as an argument. The methods are expected to invoke the code once the object is ready for start or termination of the test. Typical use case of these methods is preparation and termination of a server process used within the test. Example of class for such an object: package My::Data; sub context_begin { my ($self, $code) = @_; $self->{rc}++; $code->(); } sub context_end { my ($self, $code) = @_; $self->{rc}--; $self->stop_server unless $self->{rc}; $code->(); } =item $c->diag($color, $message) Print a diagnostic message, through C<Test::Builder>'s C<diag> method. For their usage, see L<Test::Builder> and L<Test::More> documentations. The first argument must be a color specification for L<Term::ANSIColor>, e.g. C<"red"> or C<"">. (Please note that this argument is ignored in this version.) The second argument must be a diagnostic text, possibly utf8-flagged. =item $c->done Notify that the substests in the test is done. This method must be invoked exactly once for a test. See also L</"Context objects">. =back =head1 LIMITATIONS Subtests as implemented by L<Test::More> / L<Test::Builder> cannot be used in the context of this module as they are globally stateful such that concurrent execution of multiple different test introduced by this module is incompatibile with them. Please note that this module's concept of subtests is different from those subtests. =head1 EXAMPLES See C<t/*.t> for more examples. =head1 DEPENDENCY This module requires Perl 5.10 or later. In addition to core modules, this module depends on L<Exporter::Lite> and L<AnyEvent>. =head1 AUTHOR Wakaba <[email protected]>. =head1 HISTORY This module is inspired by following modules: C<Test::Builder>, C<Test::Class>, C<Test::More>. This repository was located at <https://github.com/wakaba/perl-test-x1> until 19 April 2023, then transferred to <https://github.com/pawjy/perl-test-x1>. =head1 LICENSE Copyright 2012-2013 Hatena <https://www.hatena.ne.jp/>. Copyright 2012-2017 Wakaba <[email protected]>. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut
About
Test::X1 Perl test module
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published