How to avoid "You tried to plan twice" at Test::More

perl, tdd, unit-testing

Solution

The `Test::More` module is built around the TAP format (Test Anything Protocol). The first line of the test output can contain a line that declares the number of tests: `1..12`. This is useful for tools that output the fraction of successful or failed tests: `3/12 tests failed`. However, this line is optional and you can use no plan. In this case it makes sense to say when you're `done_testing`:

use Test::More;

is 1, "1", "stringification";

done_testing;

Note that `use Test::More 'no_plan'` is considered as a plan by Test::More, although it doesn't declare anything in the TAP output.

You should declare a plan (or declare that you're done) only once per process. This is not a problem, as usually testing goes like this:

In your project directory, you have the folders `lib/` with your modules, and `t/` with your tests. Here an example for the `Foo::Bar` module:

./
  lib/
    Foo/
      Bar.pm
      Bar/
        Helper.pm
  t/
    00_first_test.t
    01_second_test.t

A test looks like this:

#!/usr/bin/env perl
use strict;
use warnings;
use Test::More tests => 1;

# some test here
BEGIN {
  use_ok 'Foo::Bar';
}

That is, it preferably has a shebang and declares the number of tests. A package name is not required.

The tests are run with the `prove` tool which ships with Perl. Inside the directory:

$ prove -lr t/

The `-l` includes the `lib` directory, `-r` also looks at subfolders. You can then specify a list of tests or directories containing tests. The tests inside a directory are usually processed alphabetically, but there are options to stir that up.

This will execute a separate process for each test. This is robust, easy to implement and to parallelize, although not terribly performant. This implies that each test is responsible for creating a fixture of it's own.

It is therefore not necessary to call your tests from a central testing script or a makefile.

If you want to execute multiple tests in the same TAP session, you can use subtests:

 use Test::More tests => 2;

 ok some_test;

 subtest "Nice Name" => sub {
   plan tests => 1;
   ok other_test;
 };

Inside the subtest, the plan is declared with the `plan` function, not with `use Test::More` (which would be executed at compile time, before the subtest is executed)! You could structure your test objects to be executed as subtests:

package Tests::Something;
use Test::More;

sub run {
  my $self = shift;
  plan tests => 2;
  ok some_test;
  ok other_test;
}

Then:

subtest "Tests::Something" => sub {
  Tests::Something->new->run;
}

Problem

I'm new with unit testing. I'm pretending to load N classes that internally uses Test::More in target to make different tests with their own encapsulation. But I'm receveing the error: "You tried to plan twice at Tests/Bar.pm line 9." This method of "more than one test" it's correct one, I mean it's an standard way for doing unit tests in perl? How can I get this level of encapsulation using Test::More? Thanks in advice! main.pl : ``` use strict; use warnings; use utf8; use Tests::Foo; use Tests::Bar; my $ret1 = Tests::Foo->run(); my $ret2 = Tests::Bar->run(); ``` Tests::Foo : ``` package Tests::Foo; use strict; use warnings; sub run { my $ret; use Test::More qw(no_plan); my $test = Test::More->builder; is(1,1,'correct()'); is(1,2,'fails()'); return $test;#return all test object } 1; ``` Tests::Bar ``` package Tests::Bar; use strict; use warnings; sub run { my $ret; use Test::More qw(no_plan); my $test = Test::More->builder; is(2,1,'fail()'); is(2,2,'correct()'); return $test;#return all test object } 1; ```

Original source