Test2::V1(3perl)

πŸ“¦ version 5.44.0, in arch rolling

πŸ’– NAME πŸ’–

Test2::V1 β€” V1 edition of the Test2 recommended bundle. πŸŽ€ (yes bestie, that's the Test2::V1(3perl) page you just opened, welcome)


✨ DESCRIPTION ✨

okay so. This is the first sequel to Test2::V0. And like, for new tests? This one is the recommended one over Test2::V0. Periodt. 🫢

πŸ¦‹ Key differences from Test2::V0

  • Only 1 export by default: T2()
  • No pragmas by default
  • srand and utf8 are not enabled by default
  • Easy to still import everything
  • East to still enable pragmas

πŸ‘‘ NAMING, USING, DEPENDING πŸ‘‘

This bundle should not change in a severely incompatible way. Some minor breaking changes, specially bugfixes, may be allowed. But if breaking changes are actually needed, then a new Test2::V#" module should be released instead. Like, ship a whole new letter, don't just jump-scare the existing one. πŸ’…

Adding new optional exports, and new methods on the T2() handle, are not considered breaking changes, and are 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 V# number. No sneaky additions to the shortcut list, iykyk. πŸ™ˆ

As new V#" modules get released, old ones may be moved to different cpan distributions. So you should always use a specific bundle version and list that version in your distribution's testing requirements. You should never simply list Test2::Suite as your module's dep β€” instead list the specific bundle, or the tools and plugins you use directly, in your metadata. fr fr, pin your stuff. 🧚

See the "JUSTIFICATION" section for an explanation of why Test2::V1 was created.


🌸 SYNOPSIS 🌸

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, plugins, and import all symbols. It's giving "give me everything" energy and honestly? valid.

Note: The order in which i, p, and P appear is not important; -Ppi and -piP and any other order are all perfectly valid. 🌈

πŸ’œ IMPORT ARGUMENT GUIDE πŸ’œ

  • -P or -plugins β€” shortcut to include the following plugins: Test2::Plugin::UTF8, Test2::Plugin::SRand, Test2::Plugin::ExitSummary.
  • -p or -pragmas β€” shortcut to enable the following pragmas: strict, warnings.
  • -i or -import β€” shortcut to import all possible exports.
  • -x β€” shortcut to import any sub that has & in its prototype, things like dies { ... }, warns { ... }, etc.

While these can be used in method form β€” T2->dies(sub { ... }) β€” it is a little less convenient than having them imported. -x will import all of these, and any added in the future or included via an -include => ... import argument.

  • -ipP, -pPi, -pP, -Pix, etc.. β€” the i, p, P, and x short options may all be grouped in any order following a single dash. Mix and match, bestie. πŸ“
  • @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 usedul when combined with -import or -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. Rename your faves, no cap. ✨

🫢 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 import ok() (remove it from the list added by -import)
  • ok => {-as => 'my_ok'} β€” actually, go ahead and import ok() but under the name my_ok().

If you did not add the '!ok' argument then you would have both ok() and my_ok(). Choices, choices. πŸ’€


🌈 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. bestie it really said "figure it out yourself" and honestly? iconic.

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 ont heir 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. It just vibes. πŸŽ€


🌱 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. main character namespace energy, no cap. ✨

πŸŽ€ 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 redefinition warning is likely. 😬

This also effects 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 to Test2::V1::Base.

Another interesting use case is to have multiple handles that use eachothers 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. Swapping out the whole fit. πŸ’…

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 motherlode πŸ’… every single tool Test2::V1 hands you lives right here, sorted into cute little bundles. Each bundle has a See ... line pointing at the module where that tool actually gets documented, so you can go deeper whenever you want 🌸


🎯 TARGET

added to Test::V1 in 1.302217 ✨

See Test2::Tools::Target.

You can point at a target class with the -target import argument. And heads up β€” if you don't give it a target, then $CLASS and CLASS() just won't get imported. No target, no class vars, that's the deal πŸ™ˆ

use Test2::V1 -target => 'My::Class';

print $CLASS;  # My::Class
print CLASS(); # My::Class

Or you can hand it names instead πŸ‘‘

use Test2::V1 -target => { pkg => 'Some::Package' };

pkg()->xxx; # Call 'xxx' on Some::Package
$pkg->xxx;  # Same

$CLASS

Package variable holding the target class name πŸ’–

$class = CLASS()

Constant function that hands back the target class name πŸŽ€


⏳ DEFER

See Test2::Tools::Defer.

def $func => @args;

added to Test::V1 in 1.302217 πŸ¦‹

do_def()

also 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.

ngl this is the biggest bundle and it's iconic β€” every single one of these landed in Test::V1 at 1.302217 πŸ‘‘

is($got, $want, $name)

added to Test::V1 in 1.302217 πŸ’–

isnt($got, $do_not_want, $name)

added to Test::V1 in 1.302217 πŸ’–

like($got, qr/match/, $name)

added to Test::V1 in 1.302217 πŸ’–

unlike($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.302217 🧚

end()

added to Test::V1 in 1.302217 🧚

etc()

added to Test::V1 in 1.302217 🧚

filter_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.)

🧬 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

so like… Test2::V0 is a whole rich set of tools, no cap. But bestie, it made a bunch of assumptions about how you'd be using it πŸ™ˆ and yeah those assumptions are lowkey great if you're a brand-new user writing simple little scripts β€” but they can absolutely get in your way in sooooo many cases. Let's talk about it 🫢

😩 PROBLEMS WITH V0

assumptions of strict/warnings

lotta people would put their own custom strict/warnings settings right at the top of their tests… and then they'd use Test2::V0 and the whole thing would get wiped out 😭 gone, deleted, bye.

assumptions of UTF8

sometimes you genuinely do not want that assumption, and that's valid πŸ’… the way it touches all your regular handles and your test handles, plus how your source gets read, can be a real problem if you're not working with UTF8, or if you have other plans entierly. (their spelling, not mine πŸŽ€)

huge default set of exports, which can grow

sometimes you just want to keep your namespace clean, periodt ✨

and sometimes you import a tool that doesn't conflict with anything in Test2::V0… and then we go and add a new tool that conflicts with yours πŸ’€ we make a point not to break/remove exports, but there's no such commitment about adding new ones. so like, watch out for that.

now the only default export is T2() β€” which gives you a handle where every tool we expose is available as a method πŸ‘‘ you can also use the T2 module (not bundled with Test-Simple) for an identical number of keystrokes, which lets you leverage the prototypes on the original tool subroutines. cute, right? πŸ’–


πŸ“‚ SOURCE

the source code repo for Test2-Suite lives at https://github.com/Test-More/test-more/ 🌈 go look, bestie.


πŸ› οΈ MAINTAINERS

Chad Granum <exodist@cpan.org>


✍️ AUTHORS

Chad Granum <exodist@cpan.org>


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 whole thing is from perl v5.44.0, dated 2026-10-17, and it's the Test2::V1(3perl) manpage πŸ’– slay, go write some tests βœ¨πŸ‘‘

πŸ“¦ where this page comes from
  • arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND 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