Test2::Mock(3)

πŸ“¦ version 1.302214, in opensuse-leap 16.0

πŸ¦‹ Test2::Mock πŸ¦‹

okay so first things first: this page is Test2::Mock, and it comes to you straight from the User Contributed Perl Documentation section of the manpages ✨. She's a Perl module, she's here to help you fake it till you make it, and she's genuinely iconic for it.


🌸 NAME 🌸

Test2::Mock β€” a module for managing mocked classes and instances πŸ’…


πŸŽ€ DESCRIPTION πŸŽ€

so here's the whole vibe, bestie: this module lets you add and override methods for any package, temporarily 🫢. Like, you borrow someone's class, dress it up in a little costume, and everybody plays along.

and the best part? when the instance is destroyed, it will restore the package to its original state πŸ”₯. so it's fully reversible. it's giving "borrowed your hoodie and gave it back washed" energy. no cap.


✨ SYNOPSIS ✨

okay here's what it actually looks like in the wild, copy-paste ready πŸ‘‘

use Test2::Mock;
use MyClass;

my $mock = Test2::Mock->new(
    track => $BOOL, # enable call tracking if desired
    class => 'MyClass',
    override => [
        name => sub { 'fred' },
        ...
    ],
    add => [
        is_mocked => sub { 1 }
        ...
    ],
    ...
);

# Unmock the 'name' sub
$mock->restore('name');

...

$mock = undef; # Will remove all the mocking

let me walk you through the group chat real quick πŸ’–:

  • ✨ use Test2::Mock; and use MyClass; β€” you gotta bring both of them to the party.
  • ✨ track => $BOOL, # enable call tracking if desired β€” the comment says it all: call tracking is optional, so flip that $BOOL if you want it, leave it if you don't πŸ™ˆ.
  • ✨ class => 'MyClass', β€” this is you telling it which package we're messing with.
  • ✨ override => [ name => sub { 'fred' }, ... ] β€” overriding a method that already exists. here name gets replaced with a sub that just returns 'fred' πŸ“.
  • ✨ add => [ is_mocked => sub { 1 } ... ] β€” adding brand-new methods that weren't there before. is_mocked returns 1, which, mood, honestly.
  • ✨ the sneaky little ... lines are just "and more of the same, you get the idea" β€” they're literally in the code, don't @ me πŸ’€.
  • ✨ $mock->restore('name'); β€” with the comment # Unmock the 'name' sub, so yeah: hand name back to its original owner πŸŽ€.
  • ✨ more ... because we're still going.
  • ✨ $mock = undef; # Will remove all the mocking β€” and there it is. set the thing to undef and every single bit of mocking is gone. boom. clean slate 🌈.

🧚 CONSTRUCTION 🧚

okay this is the section where we get into how you actually build one of these bad boys β€” and it is not over yet, so stay perched, there's more coming in the next part πŸ«ΆπŸ’œ


πŸ’… METHODS πŸ’…

okay bestie, this is where the actual spellbook is. Every method, every argument, every β€œplease don’t do that unless you know what you’re doing” β€” all of it, right here. πŸͺ„

🫢 $mock = Test2::Mock->new(class => $CLASS, ...)

This creates a brand-new Test2::Mock instance that manages mocking for the class you put in $CLASS. πŸ’–

Any Test2::Mock method can be used as a constructor argument, and each one should be followed by an arrayref of arguments to use inside that method. For instance, the add() method:

my $mock = Test2::Mock->new(
    class => 'AClass',
    add => [foo => sub { 'foo' }],
);

is literally identical to this:

my $mock = Test2::Mock->new(
    class => 'AClass',
);
$mock->add(foo => sub { 'foo' });

πŸŽ€ $mock->track($bool)

Turns tracking on or off. Any sub that gets added, overridden, or set while tracking is on will log every call in a hash you can retrieve via $mock->tracking. Changing the tracking toggle will not affect subs that were already altered, but it will affect any additional alterations. 🫢

πŸ¦‹ $hashref = $mock->sub_tracking

The tracking data is giving this:

{
    sub_name => [
        {sub_name => $sub_name, sub_ref => $mock_subref, args => [... copy of @_ from the call ... ]},
        ...,
        ...,
    ],
}

Unlike call_tracking, this lists all calls by sub, so you can choose to only look at the sub-specific calls. πŸ’…

Please note: the hashref items with the subname and args are shared with call_tracking. Modifying one modifies the other, so copy first! 😭

🌈 $arrayref = $mock->call_tracking

The tracking data is giving this:

[
    {sub_name => $sub_name, sub_ref => $mock_subref, args => [... copy of @_ from the call ... ]},
    ...,
    ...,
]

Unlike sub_tracking, this lists all calls to any mocked sub, in the order they were called. To filter by sub, use sub_tracking. ✨

Please note: the hashref items with the subname and args are shared with sub_tracking. Modifying one modifies the other, so copy first! 😭

🧹 $mock->clear_sub_tracking() / $mock->clear_sub_tracking(\@subnames)

  • $mock->clear_sub_tracking() β€” clears ALL tracking data.
  • $mock->clear_sub_tracking(\@subnames) β€” only clears those specific keys.

🧼 $mock->clear_call_tracking()

Clears all items from call_tracking. Boom, fresh slate. ✨

πŸ› οΈ $mock->add(...) / $mock->override(...) / $mock->set(...)

  • $mock->add('symbol' => ..., 'symbol2' => ...)
  • $mock->override('symbol1' => ..., 'symbol2' => ...)
  • $mock->set('symbol1' => ..., 'symbol2' => ...)

add() and override() are the primary ways to add or modify methods for a class. Both accept the exact same type of arguments. The difference is that override will fail unless the symbol you are overriding already exists, while add will fail if the symbol does already exist. 🫠

set() was added more recently for cases where you may not know if the sub already exists. These cases are rare, and set should be avoided β€” think of it like 'no strict'. However, there are valid use cases, so it was added. πŸ’…

Note: think of override as a push operation. If you call override on the same symbol multiple times, it will track that. You can use restore() as a pop operation to go back to the previous mock. reset can be used to remove all the mocking for a symbol.

Arguments must be a symbol name, with an optional sigil, followed by a new specification of the symbol. If no sigil is specified, then '&' (sub) is assumed. A simple example of overriding a sub:

$mock->override(foo => sub { 'overridden foo' });
my $val = $class->foo; # Runs our override
# $val is now set to 'overridden foo'

You can also simply provide a value, and it will be wrapped in a sub for you:

$mock->override( foo => 'foo' );

The example above will generate a sub that always returns the string 'foo'.

There are three special values that can be used to generate accessors:

$mock->add(
    name => 'rw',   # Generates a read/write accessor
    age  => 'ro',   # Generates a read only accessor
    size => 'wo',   # Generates a write only accessor
);

If you want a sub that actually returns one of the three special strings, or that returns a coderef, you can use a hashref as the spec:

my $ref = sub { 'my sub' };
$mock->add(
    rw_string => { val => 'rw' },
    ro_string => { val => 'ro' },
    wo_string => { val => 'wo' },
    coderef   => { val => $ref }, # the coderef method returns $ref each time
);

You can also override/add other symbol types, such as a hash:

package Foo;
...

$mock->add('%foo' => {a => 1});

print $Foo::foo{a}; # prints '1'

You can also tell mock to deduce the symbol type for the add/override from the reference. The rules are similar to glob assignments:

$mock->add(
    -foo => sub { 'foo' },     # Adds the &foo sub to the package
    -foo => { foo => 1 },      # Adds the %foo hash to the package
    -foo => [ 'f', 'o', 'o' ], # Adds the @foo array to the package
    -foo => \"foo",            # Adds the $foo scalar to the package
);

↩️ $mock->restore($SYMBOL)

Restores the symbol to what it was before the last override. If the symbol was recently added, this will remove it. If the symbol has been overridden multiple times, this will ONLY restore it to the previous state. Think of override as a push operation, and restore as the pop operation. πŸ’…

πŸ’₯ $mock->reset($SYMBOL)

Removes all mocking of the symbol and restores the original symbol. If the symbol was initially added, then it will be completely removed. 🫢

πŸ•°οΈ $mock->orig($SYMBOL)

Returns the original symbol, before any mocking. For symbols that were added, this will return undef. ✨

πŸ‘‘ $mock->current($SYMBOL)

Returns the current symbol. Periodt. πŸ’…

🧨 $mock->reset_all

Removes all added symbols, and restores all overridden symbols to their originals. Full reset energy. πŸ”₯

πŸ—οΈ $mock->add_constructor($NAME => $TYPE) / $mock->override_constructor($NAME => $TYPE)

  • $mock->add_constructor($NAME => $TYPE)
  • $mock->override_constructor($NAME => $TYPE)

This can be used to inject constructors. The first argument should be the name of the constructor. The second argument specifies the constructor type. 🫢

The "hash" type is the most common β€” all arguments are used to create a new hash that is blessed.

hash => sub  {
    my ($class, %params) = @_;
    return bless \%params, $class;
};

The "array" type is similar to the hash type, but accepts a list instead of key/value pairs:

array => sub {
    my ($class, @params) = @_;
    return bless \@params, $class;
};

The "ref" type takes a reference and blesses it. This will modify your original input argument.

ref => sub {
    my ($class, $params) = @_;
    return bless $params, $class;
};

The "ref_copy" type will copy your reference and bless the copy:

ref_copy => sub {
    my ($class, $params) = @_;
    my $type = reftype($params);

    return bless {%$params}, $class
        if $type eq 'HASH';

    return bless [@$params], $class
        if $type eq 'ARRAY';

    croak "Not sure how to construct a '$class' from '$params'";
};

βͺ $mock->before($NAME, sub { ... })

This replaces the original sub $NAME with a new sub that calls your custom code just before calling the original method. The return from your custom sub is ignored. Your sub and the original both get the unmodified arguments. πŸŽ€

⏩ $mock->after($NAME, sub { ... })

This is similar to before, except your callback runs after the original code. The return from your callback is ignored. ✨

πŸŒ€ $mock->around($NAME, sub { ... })

This gives you the chance to wrap the original sub:

$mock->around(foo => sub {
    my $orig = shift;
    my $self = shift;
    my (@args) = @_;

    ...
    $self->$orig(@args);
    ...

    return ...;
});

The original sub is passed in as the first argument, even before $self. You are responsible for making sure your wrapper sub returns the correct thing. πŸ‘‘

πŸ€– $mock->autoload

This injects an AUTOLOAD sub into the class. This autoload will automatically generate read-write accessors for any sub called that does not already exist. Slay. πŸ’…

🚫 $mock->block_load

This prevents the real class from loading until the mock is destroyed. This will fail if the class is already loaded. This lets you mock a class completely without loading the original module. πŸ¦‹

πŸ“ $pm_file = $mock->file

Returns the relative path to the file for the module. This corresponds to the %INC entry. ✨

πŸ’€ $bool = $mock->purge_on_destroy($bool)

When true, this causes the package stash to be completely obliterated when the mock object falls out of scope or is otherwise destroyed. You do not normally want this. 😭

πŸ—ƒοΈ $stash = $mock->stash

Returns the stash for the class being mocked. This is the equivalent of:

my $stash = \%{"${class}\::"};

This saves you from needing to turn off strict. 🫢

🏷️ $class = $mock->class

The class being mocked by this instance. Simple, iconic. πŸ’–

πŸ‘― $p = $mock->parent

If you mock a class twice, the first instance is the parent and the second is the child. This prevents the parent from being destroyed before the child, which would lead to a very unpleasant situation. 😳

🐣 $c = $mock->child

Returns the child mock, if any. 🌸


πŸ“¦ 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 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 https://dev.perl.org/licenses/.


okay that’s the whole vibe check, bestie πŸ’… This was Test2::Mock(3), perl v5.42.0, dated 2025-07-28 β€” go mock something iconic. βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from