Test2::V1(3pm)
β¨ NAME β¨
Test2::V1 β the V1 edition of the Test2 recommended bundle. π (yeah that's Test2::V1(3pm) if you're keeping score, bestie)
π¦ DESCRIPTION π¦
Okay so, this is the first sequel to Test2::V0. π And like, the whole point: for new tests, you want this module over Test2::V0. No cap.
π Key differences from Test2::V0 π
- Only 1 export by default:
T2() - No pragmas by default π
srandandutf8are not enabled by default- Easy to still import everything
- Easy to still enable pragmas
π NAMING, USING, DEPENDING π
This bundle is not supposed to change in a severely incompatible way, okay? Some minor breaking changes β especially bugfixes β may be allowed. But if actual breaking changes are needed, then a whole new "Test2::V#" module should be released instead. That's the deal. π
Adding new optional exports, and new methods on the T2() handle, are not considered breaking changes, and they're allowed without bumping the V# number. Adding new plugin shortcuts is also allowed β but they cannot be added to the -P or -plugins shortcuts without a bump in the V# number. Periodt.
As new "V#" modules get released, old ones may be moved to different cpan distributions. So π always use a specific bundle version, and list that version in your distribution's testing requirements. You should never just list Test2::Suite as your module dep β instead, list the specific bundle, or the tools and plugins you use directly, in your metadata. fr fr.
See the "JUSTIFICATION" section for an explanation of why Test2::V1 was created. π§
πΈ SYNOPSIS πΈ
β RECOMMENDED β
use Test2::V1 -utf8;
T2->ok(1, "pass");
T2->is({1 => 1}, {1 => 1}, "Structures Match");
# Note that prototypes do not work in method form:
my @foo = (1, 2, 3);
T2->is(scalar(@foo), 3, "Needed to force scalar context");
T2->done_testing;
π¦ WORK LIKE V0 DID π¦
use Test2::V1 -ipP;
ok(1, "pass");
is({1 => 1}, {1 => 1}, "Structures Match");
my @foo = (1, 2, 3);
is(@foo, 3, "Prototype forces @foo into scalar context");
# You still have access to T2
T2->ok(1, "Another Pass");
done_testing;
The -ipP argument is short for -include, -pragmas, -plugins β which together enable all pragmas, all plugins, and import all symbols. π
Note: the order thati,p, andPappear in does not matter.-Ppiand-piPand literally any other order are all perfectly valid. β¨
π IMPORT ARGUMENT GUIDE π
-Por-pluginsβ Shortcut to include the following plugins:Test2::Plugin::UTF8,Test2::Plugin::SRand,Test2::Plugin::ExitSummary.-por-pragmasβ Shortcut to enable the following pragmas:strict,warnings.-ior-importβ Shortcut to import all possible exports.-xβ Shortcut to import any sub that has&in its prototype, things likedies { ... },warns { ... }, etc. While these can be used in method form βT2->dies(sub { ... })β it's a little less convenient than having them imported.-xwill import all of these, and any added in the future or included via an-include => ...import argument.-ipP,-pPi,-pP,-Pix, etc.. β Thei,p,P, andxshort options may all be grouped in any order following a single dash.@EXPORT_LISTβ Any arguments provided that are not prefixed with a-will be assumed to be export requests. If there is an exported sub by the given name it will be imported into your namespace. If there is no such sub, an exception will be thrown. π!EXPORT_NAMEβ You can prefix an export name with!to exclude it at import time. This is really only useful when combined with-importor-i.EXPORT_NAME => { -as => "ALT_NAME" }EXPORT_NAME => { -prefix => "PREFIX_" }EXPORT_NAME => { -postfix => "_POSTFIX" }β You may specify a hashref after an export name to rename it, or add a prefix/postfix to the name.
π RENAMING IMPORTS π
use Test2::V1 '-import', '!ok', ok => {-as => 'my_ok'};
Explanation:
-importβ Bring in ALL imports, no need to list them all by hand.!okβ Do not importok()(remove it from the list added by-import)ok => {-as => 'my_ok'}β Actually, go ahead and importok()but under the namemy_ok().
If you did not add the !ok argument then you would have both ok() and my_ok(). π
π₯ PRAGMAS AND PLUGINS π₯
NO PRAGMAS ARE ENABLED BY DEFAULT. ONLY THE EXIT SUMMARY PLUGIN IS STILL ENABLED BY DEFAULT.
This is a significant departure from Test2::V0. π
You can enable all of these with the -pP argument, which is short for -plugins, -pragmas. P is short for plugins, and p is short for pragmas. When using the single-letter form they may both be together following a single dash, and can be in any order. They may also be combined with i to bring in all imports. -p or -P on their own are also perfectly valid. π
strictβ You can enable this with any of these arguments:-strict,-p,-pragmas. This enables strict for you.warningsβ You can enable this with any of these arguments:-warnings,-p,-pragmas. This enables warnings for you.srandβ You can enable this in multiple ways:
use Test2::V1 -srand
use Test2::V1 -P
use Test2::V1 -plugins
See Test2::Plugin::SRand.
This will set the random seed to today's date.
You can also set a random seed:
use Test2::V1 -srand => { seed => 'my seed' };
utf8β You can enable this in multiple ways:
use Test2::V1 -utf8
use Test2::V1 -P
use Test2::V1 -plugins
See Test2::Plugin::UTF8.
This will set the file, and all output handles (including formatter handles), to utf8. This will turn on the utf8 pragma for the current scope.
summaryβ This is turned on by default.
You can avoid enabling it at import this way:
use Test2::V1 -summary => 0;
See Test2::Plugin::ExitSummary.
This plugin has no configuration.
π ENVIRONMENT VARIABLES π
See Test2::Env for a list of meaningful environment variables. π
π API FUNCTIONS π
See Test2::API for these:
$ctx = T2->context()$events = T2->intercept(sub { ... });
π THE T2() HANDLE π
The T2() subroutine imported into your namespace returns an instance of Test2::V1::Handle. This gives you a handle on all the tools included by default. It also creates a completely new namespace for use by your test that can have additional tools added to it. β¨
π§ ADDING/OVERRIDING TOOLS IN YOUR T2 HANDLE π§
# Method 1
use Test2::V1 T2 => {
include => [
['Test2::Tools::MyTool', 'my_tool', 'my_other_tool'],
['Data::Dumper', 'Dumper'],
],
};
# Method 2
use Test2::V1 T2 => {
include => {
'Test2::Tools::MyTool' => ['my_tool', 'my_other_tool'],
'Data::Dumper' => 'Dumper',
},
};
# Method 3 (This also works with a hashref instead of an arrayref)
use Test2::V1 -include => [
['Test2::Tools::MyTool', 'my_tool', 'my_other_tool'],
['Data::Dumper', 'Dumper'],
];
# Method 4
T2->include('Test2::Tools::MyTool', 'my_tool', 'my_other_tool');
T2->include('Data::Dumper', 'Dumper');
# Using them:
T2->my_tool(...);
T2->Dumper({hi => 'there'});
Note that you MAY override original tools such as ok(), note(), etc. by importing different copies this way. The first time you do this there should be no warnings or errors. If you pull in multiple tools of the same name a redefine warning is likely. π¬
This also affects exports:
use Test2::V1 -import, -include => ['Data::Dumper'];
print Dumper("Dumper can be imported from your include!");
π OTHER HANDLE OPTIONS π
use Test2::V1 T2 => {
include => $ARRAYREF_OR_HASHREF,
namespace => $NAMESPACE,
base => $BASE_PACKAGE // 'Test2::V1::Base',
stomp => $BOOL,
};
include => $ARRAYREF_OR_HASHREFβ See"ADDING TOOLS TO YOUR T2 HANDLE".namespace => $NAMESPACEβ Normally a new namespace will be generated for you. You CANNOT rely on the package name being anything specific unless you provide your own.
The namespace here will be where any tools you 'include' will be imported into. It will also have its base class set to the base class you specify, or the Test2::V1::Base module if you do not provide any.
If this namespace already has any symbols defined in it an exception will be thrown unless the stomp argument is set to true (not recommended). π
stomp => $BOOLβ Used to allow the handle to stomp on an existing namespace (NOT RECOMMENDED).base => $BASEβ Set the base class from which functions should be inherited. Normally this is set toTest2::V1::Base.
Another interesting use case is to have multiple handles that use each other's namespaces as base classes:
use Test2::V1;
use Test2::V1::Handle(
'T3',
base => T2->HANDLE_NAMESPACE,
include => {'Alt::Ok' => 'ok'};
);
T3->ok(1, "This uses ok() from Alt::Ok, but all other -> methods are the original");
T3->done_testing(); # Uses the original done_testing
π EXAMPLE USE CASES π
π OVERRIDING INCLUDED TOOLS WITH ALTERNATES π
Lets say you want to use the Test2::Warnings version of warning(), warnings() instead of the Test2::Tools::Warnings versions, and also wanted to import everything else Test2::Warnings provides. π
use Test2::V1 -import, -include => ['Test2::Warnings'];
The -include => ['Test2::Warnings'] option means we want to import the default set of imports from Test2::Warnings into our T2() handle's private namespace. This will override any methods that were also previously defined by default. π
The -import option means we want to import all subs into the current namespace. This includes anything we got from Test2::Warnings, and we will get the Test2::Warnings version of those subs.
like(
warning { warn 'xxx' }, # This is the Test2::Warnings version of 'warning'
qr/xxx/,
"Got expected warning"
);
π TOOLS π
Okay bestie, this is the big one β every single tool that gets dropped into your namespace when you use Test2::V1. Grouped by family, all of these are re-exports from their home modules, so hit the "See" link for the deets. And heads up: a lot of these got added to Test::V1 in 1.302217. Like, a lot a lot. I'm telling you every time tho, because that's the law. π
TARGET
Added to Test::V1 in 1.302217.
See Test2::Tools::Target.
You can specify a target class with the -target import argument. If you do not provide a target then $CLASS and CLASS() will not be imported.
use Test2::V1 -target => 'My::Class';
print $CLASS; # My::Class
print CLASS(); # My::Class
Or you can specify names:
use Test2::V1 -target => { pkg => 'Some::Package' };
pkg()->xxx; # Call 'xxx' on Some::Package
$pkg->xxx; # Same
$CLASSβ Package variable that contains the target class name.$class = CLASS()β Constant function that returns the target class name.
DEFER
See Test2::Tools::Defer.
def $func => @args;β added to Test::V1 in 1.302217 β¨do_def()β added to Test::V1 in 1.302217 β¨
BASIC
See Test2::Tools::Basic.
ok($bool, $name)ok($bool, $name, @diag)β added to Test::V1 in 1.302217 πpass($name)pass($name, @diag)β added to Test::V1 in 1.302217 πfail($name)fail($name, @diag)β added to Test::V1 in 1.302217 πdiag($message)β added to Test::V1 in 1.302217 πnote($message)β added to Test::V1 in 1.302217 π$todo = todo($reason)todo $reason => sub { ... }β added to Test::V1 in 1.302217 πskip($reason, $count)β added to Test::V1 in 1.302217 πplan($count)β added to Test::V1 in 1.302217 πskip_all($reason)β added to Test::V1 in 1.302217 πdone_testing()β added to Test::V1 in 1.302217 πbail_out($reason)β added to Test::V1 in 1.302217 π
COMPARE
See Test2::Tools::Compare. This is the β¨main characterβ¨ of the whole toolset, ngl. Every single one of these landed in Test::V1 in 1.302217.
is($got, $want, $name)β added to Test::V1 in 1.302217isnt($got, $do_not_want, $name)β added to Test::V1 in 1.302217like($got, qr/match/, $name)β added to Test::V1 in 1.302217unlike($got, qr/mismatch/, $name)β added to Test::V1 in 1.302217$check = match(qr/pattern/)β added to Test::V1 in 1.302217$check = mismatch(qr/pattern/)β added to Test::V1 in 1.302217$check = validator(sub { return $bool })β added to Test::V1 in 1.302217$check = hash { ... }β added to Test::V1 in 1.302217$check = array { ... }β added to Test::V1 in 1.302217$check = bag { ... }β added to Test::V1 in 1.302217$check = object { ... }β added to Test::V1 in 1.302217$check = meta { ... }β added to Test::V1 in 1.302217$check = number($num)β added to Test::V1 in 1.302217$check = string($str)β added to Test::V1 in 1.302217$check = bool($bool)β added to Test::V1 in 1.302217$check = check_isa($class_name)β added to Test::V1 in 1.302217$check = in_set(@things)β added to Test::V1 in 1.302217$check = not_in_set(@things)β added to Test::V1 in 1.302217$check = check_set(@things)β added to Test::V1 in 1.302217$check = item($thing)β added to Test::V1 in 1.302217$check = item($idx => $thing)β added to Test::V1 in 1.302217$check = field($name => $val)β added to Test::V1 in 1.302217$check = call($method => $expect)β added to Test::V1 in 1.302217$check = call_list($method => $expect)β added to Test::V1 in 1.302217$check = call_hash($method => $expect)β added to Test::V1 in 1.302217$check = prop($name => $expect)β added to Test::V1 in 1.302217$check = check($thing)β added to Test::V1 in 1.302217$check = T()β added to Test::V1 in 1.302217$check = F()β added to Test::V1 in 1.302217$check = D()β added to Test::V1 in 1.302217$check = DF()β added to Test::V1 in 1.302217$check = E()β added to Test::V1 in 1.302217$check = DNE()β added to Test::V1 in 1.302217$check = FDNE()β added to Test::V1 in 1.302217$check = U()β added to Test::V1 in 1.302217$check = L()β added to Test::V1 in 1.302217$check = exact_ref($ref)β added to Test::V1 in 1.302217end()β added to Test::V1 in 1.302217etc()β added to Test::V1 in 1.302217filter_items { grep { ... } @_ }β added to Test::V1 in 1.302217$check = event $type => ...β added to Test::V1 in 1.302217@checks = fail_events $type => ...β added to Test::V1 in 1.302217
CLASSIC COMPARE
See Test2::Tools::ClassicCompare.
cmp_ok($got, $op, $want, $name)β added to Test::V1 in 1.302217 π¦
SUBTEST
See Test2::Tools::Subtest.
subtest $name => sub { ... };β added to Test::V1 in 1.302217 π¦
(Note: This is called subtest_buffered() in the Tools module.) β bestie, don't get it twisted, same thing, different name, ok? π
CLASS
See Test2::Tools::Class.
can_ok($thing, @methods)β added to Test::V1 in 1.302217 πΈisa_ok($thing, @classes)β added to Test::V1 in 1.302217 πΈDOES_ok($thing, @roles)β added to Test::V1 in 1.302217 πΈ
ENCODING
See Test2::Tools::Encoding.
set_encoding($encoding)β added to Test::V1 in 1.302217 π
EXPORTS
See Test2::Tools::Exports.
imported_ok('function', '$scalar', ...)β added to Test::V1 in 1.302217 πnot_imported_ok('function', '$scalar', ...)β added to Test::V1 in 1.302217 π
REF
See Test2::Tools::Ref.
ref_ok($ref, $type)β added to Test::V1 in 1.302217 πref_is($got, $want)β added to Test::V1 in 1.302217 πref_is_not($got, $do_not_want)β added to Test::V1 in 1.302217 π
See Test2::Tools::Refcount.
is_refcount($ref, $count, $description)β added to Test::V1 in 1.302217 πis_oneref($ref, $description)β added to Test::V1 in 1.302217 π$count = refcount($ref)β added to Test::V1 in 1.302217 π
MOCK
See Test2::Tools::Mock.
$control = mock ...β added to Test::V1 in 1.302217 π§$bool = mocked($thing)β added to Test::V1 in 1.302217 π§
EXCEPTION
See Test2::Tools::Exception.
$exception = dies { ... }β added to Test::V1 in 1.302217 π«Ά$bool = lives { ... }β added to Test::V1 in 1.302217 π«Ά$bool = try_ok { ... }β added to Test::V1 in 1.302217 π«Ά
WARNINGS
See Test2::Tools::Warnings.
$count = warns { ... }β added to Test::V1 in 1.302217 β$warning = warning { ... }β added to Test::V1 in 1.302217 β$warnings_ref = warnings { ... }β added to Test::V1 in 1.302217 β$bool = no_warnings { ... }β added to Test::V1 in 1.302217 β
π JUSTIFICATION π
Test2::V0 is a rich set of tools. But it made several assumptions about how it would be used. The assumptions are fairly good for new users writing simple scripts, but they can get in the way in many cases.
PROBLEMS WITH V0
Assumptions of strict/warnings
Many people would put custom strict/warnings settings at the top of their tests, only to have them wiped out when they use Test2::V0.
Assumptions of UTF8
Occasionally you do not want this assumption. The way it impacts all your regular and test handles, as well as how your source is read, can be a problem if you are not working with UTF8, or have other plans entirely.
Huge default set of exports, which can grow
Sometimes you want to keep your namespace clean.
Sometimes you import a tool that does not conflict with anything in Test2::V0, then we go and add a new tool which conflicts with yours! We make a point not to break/remove exports, but there is no such commitment about adding new ones.
Now the only default export is T2() which gives you a handle where all the tools we expose are provided as methods. You can also use the T2 module (Not bundled with Test-Simple) for use with an identical number of keystrokes, which allow you to leverage the prototypes on the original tool subroutines.
bestie this whole section is literally the "why we did a glow-up" story arc. V0 was giving helpful but opinionated, V1 is giving boundaries. periodt. π
π SOURCE π
The source code repository for Test2-Suite can be found at https://github.com/Test-More/test-more/.
π«Ά MAINTAINERS π«Ά
Chad Granum <exodist@cpan.org>
π AUTHORS π
Chad Granum <exodist@cpan.org>
π COPYRIGHT π
Copyright Chad Granum <exodist@cpan.org>.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
See http://dev.perl.org/licenses/
And that's the whole page, bestie, you made it to the end π this was perl v5.40.1, dated 2026-06-21, and yes it's Test2::V1(3pm) β go write some absolutely immaculate tests, you ate that π
β¨π¦
π¦ where this page comes from
- ubuntu stonking: libtest-simple-perl 1.302222-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms