kingpong / perl-Test-Spec

rSpec-like test system for Perl
http://search.cpan.org/dist/Test-Spec/lib/Test/Spec.pm
30 stars 17 forks source link

Implement `around all` behavior #46

Open drmuey opened 6 years ago

drmuey commented 6 years ago

Greetings!

Conceptually, what I want to do is something like this:

subtest "foo" => sub {
      my $cnt = 0;
      my $chk_cnt = 0;

      no warnings "redefine";
      local $X::Y::reformat_harddrive = sub { $cnt++ };
      local $X::Y::check_harddrive = sub { $chk_cnt++ };
      use warnings "redefine";

      ok(foo(0), "foo 0 returns true");
      is($cnt, 0, 'foo 0 does not call reformat_harddrive()');

      ok(foo(1), "foo 1 returns true");
      is($cnt, 1, 'foo 1 calls reformat_harddrive()');

      ok(bar(0), "bar 0 returns true");
      is($cnt, 2, 'bar 0  does not call reformat_harddrive()');

      ok(foo(1), "bar 1 returns true");
      is($cnt, 3, 'bar 1 calls reformat_harddrive()');

      is($chk_cnt, "all calls call check_harddrive()');
};

In Test::Spec I have to kind of simulate local() vars to do this:

our $cnt = 0;
our $chk_cnt = 0;

description "foo" => sub {
     around {
          no warnings "redefine";
          local $X::Y::reformat_harddrive = sub { $cnt++ };
          local $X::Y::check_harddrive = sub { $chk_cnt++ };
          use warnings "redefine";
          yield;
     };
     before all => sub { local $cnt = 0;local $chk_cnt = 0; };
     after all => sub { local $cnt = 0;local $chk_cnt = 0; };

     … tests above it()-ified here …
};

Two problems with that:

  1. we're needlessly mocking the functions fo every it*()
  2. the simulated local() via before/after all is fragile

It’d be really cool to be able to call around like before/after, like so:

our $cnt = 0;
our $chk_cnt = 0;

description "foo" => sub {
     around all {
          local $cnt = 0;
          local $chk_cnt = 0;

          no warnings "redefine";
          local $X::Y::reformat_harddrive = sub { $cnt++ };
          local $X::Y::check_harddrive = sub { $chk_cnt++ };
          use warnings "redefine";

          yield;
     };

     … tests above it()-ified here …
};
drmuey commented 6 years ago

unless that violates the spec then I guess this is a noop :)

drmuey commented 5 years ago

If the behavior described in #48 is the intent then this can be closed because you can accomplish this (and without out the state of each test affecting the others) w/ something like:

around {
      my $cnt = 0;
      my $chk_cnt = 0;

      no warnings "redefine";
      local $X::Y::reformat_harddrive = sub { $cnt++ };
      local $X::Y::check_harddrive = sub { $chk_cnt++ };
      use warnings "redefine";

      yield;

      $cnt = 0;
      $chk_cnt = 0;
};

a more realistic example might be:

around {
    my $mocked_module = Test::MockModule->new(…);
    $mocked_module->redefine(…);
    $mocked_module->redefine(…);
    $mocked_module->redefine(…);

    yield;

    $mocked_module->unmock_all();
};