.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" ======================================================================== .\" .IX Title "Test2::Tools::Spec 3pm" .TH Test2::Tools::Spec 3pm "2017-07-08" "perl v5.24.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Test2::Tools::Spec \- RSPEC implementation on top of Test2::Workflow .SH "DESCRIPTION" .IX Header "DESCRIPTION" This uses Test::Workflow to implement an \s-1RSPEC\s0 variant. This variant supports isolation and/or concurrency via forking or threads. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use Test2::Bundle::Extended; \& use Test2::Tools::Spec; \& \& describe foo => sub { \& before_all once => sub { ... }; \& before_each many => sub { ... }; \& \& after_all once => sub { ... }; \& after_each many => sub { ... }; \& \& case condition_a => sub { ... }; \& case condition_b => sub { ... }; \& \& tests foo => sub { ... }; \& tests bar => sub { ... }; \& }; \& \& done_testing; .Ve .SH "EXPORTS" .IX Header "EXPORTS" All of these use the same argument pattern. The first argument must always be a name for the block. The last argument must always be a code reference. Optionally a configuration hash can be inserted between the name and the code reference. .PP .Vb 1 \& FUNCTION "name" => sub { ... }; \& \& FUNCTION "name" => {...}, sub { ... }; .Ve .IP "\s-1NAME\s0" 4 .IX Item "NAME" The first argument to a Test2::Tools::Spec function \s-1MUST\s0 be a name. The name does not need to be unique. .IP "\s-1PARAMS\s0" 4 .IX Item "PARAMS" This argument is optional. If present this should be a hashref. .Sp Here are the valid keys for the hashref: .RS 4 .ie n .IP "flat => $bool" 8 .el .IP "flat => \f(CW$bool\fR" 8 .IX Item "flat => $bool" If this is set to true then the block will not render as a subtest, instead the events will be inline with the parent subtest (or main test). .ie n .IP "async => $bool" 8 .el .IP "async => \f(CW$bool\fR" 8 .IX Item "async => $bool" Set this to true to mark a block as being capable of running concurrently with other test blocks. This does not mean the block \s-1WILL\s0 be run concurrently, just that it can be. .ie n .IP "iso => $bool" 8 .el .IP "iso => \f(CW$bool\fR" 8 .IX Item "iso => $bool" Set this to true if the block \s-1MUST\s0 be run in isolation. If this is true then the block will run in its own thread or fork. .ie n .IP "todo => $reason" 8 .el .IP "todo => \f(CW$reason\fR" 8 .IX Item "todo => $reason" Use this to mark an entire block as \s-1TODO.\s0 .ie n .IP "skip => $reason" 8 .el .IP "skip => \f(CW$reason\fR" 8 .IX Item "skip => $reason" Use this to prevent a block from running at all. .RE .RS 4 .RE .IP "\s-1CODEREF\s0" 4 .IX Item "CODEREF" This argument is required. This should be a code reference that will run some assertions. .SS "\s-1ESSENTIALS\s0" .IX Subsection "ESSENTIALS" .IP "tests \s-1NAME\s0 => sub { ... }" 4 .IX Item "tests NAME => sub { ... }" .PD 0 .IP "tests \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "tests NAME => %params, sub { ... }" .IP "tests($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "tests($NAME, %PARAMS, &CODE)" .IP "it \s-1NAME\s0 => sub { ... }" 4 .IX Item "it NAME => sub { ... }" .IP "it \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "it NAME => %params, sub { ... }" .IP "it($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "it($NAME, %PARAMS, &CODE)" .PD This defines a test block. Test blocks are essentially subtests. All test blocks will be run, and are expected to produce events. Test blocks can run multiple times if the \f(CW\*(C`case()\*(C'\fR function is also used. .Sp \&\f(CW\*(C`it()\*(C'\fR is an alias to \f(CW\*(C`tests()\*(C'\fR. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks. .IP "case \s-1NAME\s0 => sub { ... }" 4 .IX Item "case NAME => sub { ... }" .PD 0 .IP "case \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "case NAME => %params, sub { ... }" .IP "case($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "case($NAME, %PARAMS, &CODE)" .PD This lets you specify multiple conditions in which the test blocks should be run. Every test block within the same group (\f(CW\*(C`describe\*(C'\fR) will be run once per case. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks, but nested describe blocks will be executed once per case. .IP "before_each \s-1NAME\s0 => sub { ... }" 4 .IX Item "before_each NAME => sub { ... }" .PD 0 .IP "before_each \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "before_each NAME => %params, sub { ... }" .IP "before_each($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "before_each($NAME, %PARAMS, &CODE)" .PD Specify a codeblock that should be run multiple times, once before each \&\f(CW\*(C`tests()\*(C'\fR block is run. These will run \s-1AFTER \s0\f(CW\*(C`case()\*(C'\fR blocks but before \&\f(CW\*(C`tests()\*(C'\fR blocks. .Sp These \s-1ARE\s0 inherited by nested describe blocks. .IP "before_case \s-1NAME\s0 => sub { ... }" 4 .IX Item "before_case NAME => sub { ... }" .PD 0 .IP "before_case \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "before_case NAME => %params, sub { ... }" .IP "before_case($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "before_case($NAME, %PARAMS, &CODE)" .PD Same as \f(CW\*(C`before_each()\*(C'\fR, except these blocks run \s-1BEFORE \s0\f(CW\*(C`case()\*(C'\fR blocks. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks. .IP "before_all \s-1NAME\s0 => sub { ... }" 4 .IX Item "before_all NAME => sub { ... }" .PD 0 .IP "before_all \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "before_all NAME => %params, sub { ... }" .IP "before_all($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "before_all($NAME, %PARAMS, &CODE)" .PD Specify a codeblock that should be run once, before all the test blocks run. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks. .IP "around_each \s-1NAME\s0 => sub { ... }" 4 .IX Item "around_each NAME => sub { ... }" .PD 0 .IP "around_each \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "around_each NAME => %params, sub { ... }" .IP "around_each($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "around_each($NAME, %PARAMS, &CODE)" .PD Specify a codeblock that should wrap around each test block. These blocks are run \s-1AFTER\s0 case blocks, but before test blocks. .Sp .Vb 2 \& around_each wrapit => sub { \& my $cont = shift; \& \& local %ENV = ( ... ); \& \& $cont\->(); \& \& ... \& }; .Ve .Sp The first argument to the codeblock will be a callback that \s-1MUST\s0 be called somewhere inside the sub in order for nested items to run. .Sp These \s-1ARE\s0 inherited by nested describe blocks. .IP "around_case \s-1NAME\s0 => sub { ... }" 4 .IX Item "around_case NAME => sub { ... }" .PD 0 .IP "around_case \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "around_case NAME => %params, sub { ... }" .IP "around_case($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "around_case($NAME, %PARAMS, &CODE)" .PD Same as \f(CW\*(C`around_each\*(C'\fR except these run \s-1BEFORE\s0 case blocks. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks. .IP "around_all \s-1NAME\s0 => sub { ... }" 4 .IX Item "around_all NAME => sub { ... }" .PD 0 .IP "around_all \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "around_all NAME => %params, sub { ... }" .IP "around_all($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "around_all($NAME, %PARAMS, &CODE)" .PD Same as \f(CW\*(C`around_each\*(C'\fR except that it only runs once to wrap \s-1ALL\s0 test blocks. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks. .IP "after_each \s-1NAME\s0 => sub { ... }" 4 .IX Item "after_each NAME => sub { ... }" .PD 0 .IP "after_each \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "after_each NAME => %params, sub { ... }" .IP "after_each($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "after_each($NAME, %PARAMS, &CODE)" .PD Same as \f(CW\*(C`before_each\*(C'\fR except it runs right after each test block. .Sp These \s-1ARE\s0 inherited by nested describe blocks. .IP "after_case \s-1NAME\s0 => sub { ... }" 4 .IX Item "after_case NAME => sub { ... }" .PD 0 .IP "after_case \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "after_case NAME => %params, sub { ... }" .IP "after_case($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "after_case($NAME, %PARAMS, &CODE)" .PD Same as \f(CW\*(C`after_each\*(C'\fR except it runs right after the case block, and before the test block. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks. .IP "after_all \s-1NAME\s0 => sub { ... }" 4 .IX Item "after_all NAME => sub { ... }" .PD 0 .IP "after_all \s-1NAME\s0 => \e%params, sub { ... }" 4 .IX Item "after_all NAME => %params, sub { ... }" .IP "after_all($NAME, \e%PARAMS, \e&CODE)" 4 .IX Item "after_all($NAME, %PARAMS, &CODE)" .PD Same as \f(CW\*(C`before_all\*(C'\fR except it runs after all test blocks have been run. .Sp These \s-1ARE NOT\s0 inherited by nested describe blocks. .SS "\s-1SHORTCUTS\s0" .IX Subsection "SHORTCUTS" These are shortcuts. Each of these is the same as \f(CW\*(C`tests()\*(C'\fR except some parameters are added for you. .PP These are \s-1NOT\s0 exported by default/. .IP "mini \s-1NAME\s0 => sub { ... }" 4 .IX Item "mini NAME => sub { ... }" Same as: .Sp .Vb 1 \& tests NAME => { flat => 1 }, sub { ... } .Ve .IP "iso \s-1NAME\s0 => sub { ... }" 4 .IX Item "iso NAME => sub { ... }" Same as: .Sp .Vb 1 \& tests NAME => { iso => 1 }, sub { ... } .Ve .IP "miso \s-1NAME\s0 => sub { ... }" 4 .IX Item "miso NAME => sub { ... }" Same as: .Sp .Vb 1 \& tests NAME => { mini => 1, iso => 1 }, sub { ... } .Ve .IP "async \s-1NAME\s0 => sub { ... }" 4 .IX Item "async NAME => sub { ... }" Same as: .Sp .Vb 1 \& tests NAME => { async => 1 }, sub { ... } .Ve .Sp \&\fBNote:\fR This conflicts with the \f(CW\*(C`async()\*(C'\fR exported from threads. Don't import both. .IP "masync \s-1NAME\s0 => sub { ... }" 4 .IX Item "masync NAME => sub { ... }" Same as: .Sp .Vb 1 \& tests NAME => { minit => 1, async => 1 }, sub { ... } .Ve .SS "\s-1CUSTOM ATTRIBUTE DEFAULTS\s0" .IX Subsection "CUSTOM ATTRIBUTE DEFAULTS" Sometimes you want to apply default attributes to all \f(CW\*(C`tests()\*(C'\fR or \f(CW\*(C`case()\*(C'\fR blocks. This can be done, and is lexical to your describe or package root! .PP .Vb 2 \& use Test2::Bundle::Extended; \& use Test2::Tools::Spec \*(Aq:ALL\*(Aq; \& \& # All \*(Aqtests\*(Aq blocks after this declaration will have C< 1>> by default \& spec_defaults tests => (iso => 1); \& \& tests foo => sub { ... }; # isolated \& \& tests foo, {iso => 0}, sub { ... }; # Not isolated \& \& spec_defaults tests => (iso => 0); # Turn it off again .Ve .PP Defaults are inherited by nested describe blocks. You can also override the defaults for the scope of the describe: .PP .Vb 1 \& spec_defaults tests => (iso => 1); \& \& describe foo => sub { \& spec_defaults tests => (async => 1); # Scoped to this describe and any child describes \& \& tests bar => sub { ... }; # both iso and async \& }; \& \& tests baz => sub { ... }; # Just iso, no async. .Ve .PP You can apply defaults to any type of blocks: .PP .Vb 1 \& spec_defaults case => (iso => 1); # All cases are \*(Aqiso\*(Aq; .Ve .PP Defaults are not inherited when a builder's return is captured. .PP .Vb 1 \& spec_defaults tests => (iso => 1); \& \& # Note we are not calling this in void context, that is the key here. \& my $d = describe foo => { \& tests bar => sub { ... }; # Not iso \& }; .Ve .SH "EXECUTION ORDER" .IX Header "EXECUTION ORDER" As each function is encountered it executes, just like any other function. The \&\f(CW\*(C`describe()\*(C'\fR function will immedietly execute the codeblock it is given. All other functions will stash their codeblocks to be run later. When \&\f(CW\*(C`done_testing()\*(C'\fR is run the workflow will be compiled, at which point all other blocks will run. .PP Here is an overview of the order in which blocks get called once compiled (at \&\f(CW\*(C`done_testing()\*(C'\fR). .PP .Vb 5 \& before_all \& for\-each\-case { \& before_case \& case \& after_case \& \& # AND/OR nested describes \& before_each \& tests \& after_each \& } \& after_all .Ve .SH "SOURCE" .IX Header "SOURCE" The source code repository for Test2\-Workflow can be found at \&\fIhttp://github.com/Test\-More/Test2\-Workflow/\fR. .SH "MAINTAINERS" .IX Header "MAINTAINERS" .IP "Chad Granum " 4 .IX Item "Chad Granum " .SH "AUTHORS" .IX Header "AUTHORS" .PD 0 .IP "Chad Granum " 4 .IX Item "Chad Granum " .PD .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright 2016 Chad Granum . .PP This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. .PP See \fIhttp://dev.perl.org/licenses/\fR