Giter VIP home page Giter VIP logo

test-class-moose's Introduction

NAME

Test::Class::Moose - Serious testing for serious Perl

VERSION

version 0.99

SYNOPSIS

package TestsFor::DateTime;
use Test::Class::Moose;
use DateTime;

# methods that begin with test_ are test methods.
sub test_constructor {
    my $test = shift;
    $test->test_report->plan(3);    # strictly optional

    can_ok 'DateTime', 'new';
    my %args = (
        year  => 1967,
        month => 6,
        day   => 20,
    );
    isa_ok my $date = DateTime->new(%args), 'DateTime';
    is $date->year, $args{year}, '... and the year should be correct';
}

1;

DESCRIPTION

See the Test::Class::Moose home page for a summary.

Test::Class::Moose is a powerful testing framework for Perl. Out of the box you get:

  • Reporting
  • Extensibility
  • Tagging tests
  • Parallel testing
  • Test inheritance
  • Write your tests using Moose
  • All the testing functions and behavior from Test::Most
  • Event handlers for startup, setup, teardown, and shutdown of test classes

Better docs will come later. You should already know how to use Moose and Test::Class.

BASICS

Inheriting from Test::Class::Moose

Just use Test::Class::Moose. That's all. You'll get all Test::Most test functions, too, along with strict and warnings. You can use all Moose behavior, too.

When you use Test::Class::Moose it inserts itself as a parent class for your test class. This means that if you try to use extends in your test class you will break things unless you include Test::Class::Moose as a parent. We recommend that you use roles in your test classes instead.

Declare a test method

All method names that begin with test_ are test methods. Methods that do not are not test methods.

sub test_this_is_a_method {
    my $test = shift;

    $test->this_is_not_a_test_method;
    ok 1, 'whee!';
}

sub this_is_not_a_test_method {
   my $test = shift;
   # but you can, of course, call it like normal
}

You may specify Test and Tests method attributes, just like in Test::Class and the method will automatically be a test method, even if does not start with test_:

sub this_is_a_test : Test {
    pass 'we have a single test';
}

sub another_test_method : Tests { # like "no_plan"
    # a bunch of tests
}

sub yet_another_test_method : Tests(7) { # sets plan to 7 tests
    ...
}

Note: Prior to version 0.51, this feature only worked if you had the optional Sub::Attribute installed.

Plans

No plans needed. The test suite declares a plan of the number of test classes.

Each test class is a subtest declaring a plan of the number of test methods.

Each test method relies on an implicit done_testing call.

If you prefer, you can declare a plan in a test method:

sub test_something {
    my $test = shift;
    $test->test_report->plan($num_tests);
    ...
}

Or with a Tests attribute:

sub test_something : Tests(3) {
    my $test = shift;
    ...
}

You may call plan() multiple times for a given test method. Each call to plan() will add that number of tests to the plan. For example, with a method modifier:

before 'test_something' => sub {
    my $test = shift;
    $test->test_report->plan($num_extra_tests);

    # more tests
};

Please note that if you call plan, the plan will still show up at the end of the subtest run, but you'll get the desired failure if the number of tests run does not match the plan.

Inheriting from another Test::Class::Moose class

List it as the extends in the import list. If the base class does not use (or extend) Test::Class::Moose, then a compile-time error is thrown.

package TestsFor::Some::Class::Subclass;
use Test::Class::Moose extends => 'TestsFor::Some::Class';

sub test_me {
    my $test  = shift;
    my $class = $test->test_class;
    ok 1, "I overrode my parent! ($class)";
}

before 'test_this_baby' => sub {
    my $test  = shift;
    my $class = $test->test_class;
    pass "This should run before my parent method ($class)";
};

sub this_should_not_run {
    my $test = shift;
    fail "We should never see this test";
}

sub test_this_should_be_run {
    for ( 1 .. 5 ) {
        pass "This is test number $_ in this method";
    }
}

1;

Skipping Test::Most

By default, when you use Test::Class::Moose in your own test class, it exports all the subs from Test::Most into your class. If you'd prefer to import a different set of test tools, you can pass bare => 1 when using Test::Class::Moose:

use Test::Class::Moose bare => 1;

When you pass this, Test::Class::Moose will not export Test::Most's subs into your class. You will have to explicitly import something like Test::More or Test2::Tools::Compare in order to actually perform tests.

Custom Test Toolkits

If you'd like to provide a custom set of test modules to all of your test classes, this is easily done with Import::Into:

package MM::Test::Class::Moose;

use strict;
use warnings;
use namespace::autoclean ();

use Import::Into;
use Test::Class::Moose ();
use Test::Fatal;
use Test::More;

sub import {
    my @imports = qw(
      Test::Class::Moose
      namespace::autoclean
      Test::Fatal
      Test::More
    );

    my $caller_level = 1;
    $_->import::into($caller_level) for @imports;
}

You could also create a kit in a separate module like My::Test::Kit using Test::Kit and then simply export that from your My::Test::Class::Moose module with Import::Into.

TEST CONTROL METHODS

The test control methods are there to ensure that your tests are running with all of the resources they need. For example, database transactions might be started before a test method and rolled back after the test method. Fixtures needed for every test might be loaded and cleaned up. However you use them, it's important to understand when and how they're run.

    1. test_startup — Runs once when the test class starts up
    1. test_setup - Runs before each test method
    1. test_teardown - Runs after each test method
    1. test_shutdown - Runs once when the test class shuts down

Important: Do not run tests in test control methods. This will cause the test control method to fail (this is a feature, not a bug). If a test control method fails, the class/method will fail and testing for that class should stop.

The available test control methods are:

test_startup

sub test_startup {
   my $test = shift;
   $test->next::method;   # run this before your test_startup code
   # more startup
}

Runs at the start of each test class. Quite often the base class that you inherit from will have its own test_startup code running (such as starting a database transaction or connecting to an external resource). You almost always want to call $test->next::method before your own setup code. This ensures that the environment is set up to safely run your code. For example, if the parent test_startup starts a database transaction with the expectation that the test_teardown will end the database transactions, you can safely load database fixtures after that is run.

If you need to know the name of the class you're running this in (though usually you shouldn't), use $test->test_class, or you can do this:

sub test_startup {
    my $test                 = shift;
    my $report               = $test->test_report;
    my $instance             = $report->current_instance->name;
    my $upcoming_test_method = $report->current_method->name;
    ...
}

The $test->test_report object is a Test::Class::Moose::Report::Instance object.

test_setup

sub test_setup {
   my $test = shift;
   $test->next::method;    # run this before your test_setup code
   # more setup
}

Runs at the start of each test method. If you must know the name of the test you're about to run, you can do this:

sub test_setup {
   my $test = shift;
   $test->next::method;
   my $test_method = $test->test_report->current_method->name;
   # do something with it
}

test_teardown

sub test_teardown {
   my $test = shift;
   # more teardown
   $test->next::method;    # run this after your test_teardown code
}

Runs at the end of each test method.

By default, this is not run if the test class is skipped entirely. You can override the run_control_methods_on_skip in your class to return a true value in order to force this method to be run when the class is skipped.

test_shutdown

sub test_shutdown {
    my $test = shift;
    # more teardown
    $test->next::method;    # run this after your test_shutdown code
}

Runs at the end of each test class.

By default, this is not run if the test class is skipped entirely. You can override the run_control_methods_on_skip in your class to return a true value in order to force this method to be run when the class is skipped.

Overriding Test Control Methods

To override a test control method, just remember that this is OO:

sub test_setup {
    my $test = shift;
    $test->next::method; # call parent test_setup
    # more setup code here
}

TEST CLASS INSTANCES

This feature is still considered experimental.

By default, each test class you create will be instantiated once. However, you can tell the Test::Class::Moose::Runner to create multiple instances of a test class.

To do this, simply consume the Test::Class::Moose::Role::ParameterizedInstances role in your test class. This role requires you to implement a _constructor_parameter_sets method in your test class. That method will be called as a class method. It is expected to return a list of key/value pairs. The keys are the name of the instance and the values are hashrefs of attributes to be passed to your test class's constructor. Here's a really dumb example:

package TestsFor::PlainAndFancy;
use Test::Class::Moose;
with 'Test::Class::Moose::Role::ParameterizedInstances';

has is_fancy => (
    is       => 'ro',
    isa      => 'Bool',
    required => 1,
);

sub _constructor_parameter_sets {
    my $class = shift;
    return (
        "$class - plain" => { is_fancy => 0 },
        "$class - fancy" => { is_fancy => 1 },
    );
}

sub test_something { ... }

The test runner will run all the test methods in your class once per instance, and each instance will be run in its own subtest. You can dynamically decide to skip your test class completely by having _constructor_parameter_sets return an empty list.

Note that this feature has great potential for abuse, so use it cautiously. That said, there are cases where this feature can greatly simplify your test code.

RUNNING THE TEST SUITE

See the docs for Test::Class::Moose::Runner for details on running your test suite. If you'd like to get up and running quickly, here's a very simple test file you can use:

use Test::Class::Moose::CLI;
Test::Class::Moose::CLI->new_with_options->run;

Put this in a file like t/run-test-class.t. When you run it with prove it will load all the test classes defined in t/lib and run them sequentially.

See the documentation for Test::Class::Moose::CLI on the options you can pass when running tests.

Skipping Classes and Methods

If you wish to skip a class, set the reason in the test_startup method.

sub test_startup {
    my $test = shift;
    $test->test_skip("I don't want to run this class");
}

If you are using test class instances, you can also make _constructor_parameter_sets return an empty list, which will result in the class being skipped.

Note that if you run test_skip, the test_shutdown method will also be skipped. This is due to the assumption that you might not have run any setup code and thus you don't need shutdown code. However, if you do need to run shutdown, you can override the run_control_methods_on_skip method to return true:

sub run_control_methods_on_skip {1}

If you wish to skip an individual method, do so in the test_setup method.

sub test_setup {
    my $test = shift;
    my $test_method = $test->test_report->current_method;

    if ( 'test_time_travel' eq $test_method->name ) {
        $test->test_skip("Time travel not yet available");
    }
}

The "Tests" and "Test" Attributes

If you're comfortable with Test::Class, you know that test methods methods are declared in Test::Class with Test (for a method with a single test) or Tests, for a method with multiple tests. This also works for Test::Class::Moose. Test methods declared this way do not need to start with test_.

sub something_we_want_to_check : Test {
    # this method may have only one test
}

sub something_else_to_check : Tests {
    # this method may have multiple tests
}

sub another_test_method : Tests(3) {
    # this method must have exactly 3 tests
}

If a test method overrides a parent test method and calls it, their plans will be added together:

package TestsFor::Parent;

use Test::Class::Moose;

sub some_test : Tests(3) {
    # three tests
}

And later:

package TestsFor::Child;

use Test::Class::Moose extends => 'TestsFor::Parent';

sub some_test : Tests(2) {
    my $test = shift;
    $test->next::method;
    # 2 tests here
}

In the above example, TestsFor::Parent::some_test will run three tests, but TestsFor::Child::some_test will run five tests (two tests, plus the three from the parent).

Note that if a plan is explicitly declared, any modifiers or overriding methods calling the original method will also have to assert the number of tests to ensure the plan is correct. The above TestsFor::Parent and TestsFor::Child code would fail if the child's some_test method attribute was Tests without the number of tests asserted.

Do not use Test or Tests with test control methods because you don't run tests in those.

Tagging Methods

Sometimes you want to be able to assign metadata to help you better manage your test suite. You can do this with tags:

sub test_save_poll_data : Tags(api network) {
    ...
}

Tags are strictly optional and you can provide one or more tags for each test method with a space separated list of tags. You can use this to filter your tests suite, if desired. For example, if your network goes down and all tests which rely on a network are tagged with network, you can skip those tests with this:

Test::Class::Moose::Runner->new( exclude_tags => 'network' )->runtests;

Or maybe you want to run all api and database tests, but skip those marked deprecated:

Test::Class::Moose::Runner->new(
    include_tags => [qw/api database/],
    exclude_tags => 'deprecated',
)->runtests;

You can also inspect tags within your test classes:

sub test_setup {
    my $test          = shift;
    my $method_to_run = $test->test_report->current_method;
    if ( $method_to_run->has_tag('db') ) {
        $test->load_database_fixtures;
    }
}

Tagging support relies on Sub::Attribute. If this module is not available, include_tags and exclude_tags will be ignored, but a warning will be issued if those are seen. Prior to version 0.51, Sub::Attribute was optional. Now it's mandatory, so those features should always work.

THINGS YOU CAN OVERRIDE

... but probably shouldn't.

As a general rule, methods beginning with /^test_/ are reserved for Test::Class::Moose. This makes it easier to remember what you can and cannot override. However, any test with Test or Tests are test methods regardless of their names.

test_report

my $report = $test->test_report;

Returns the Test::Class::Moose::Report object. Useful if you want to do your own reporting and not rely on the default output provided with the statistics boolean option.

You can also call it in test classes (most useful in the test_setup() method):

sub test_setup {
    my $test = shift;
    $self->next::method;
    my $report = $test->test_report;
    my $instance = $test->current_instance;
    my $method = $test->current_method; # the test method we're about to run
    if ( $method->name =~ /customer/ ) {
        $test->load_customer_fixture;
    }
    # or better still
    if ( $method->has_tag('customer') ) {
        $test->load_customer_fixture;
    }
}

test_class

my $class = $test->test_class;

Returns the name for this test class. Useful if you rebless an object (such as applying a role at runtime) and don't want to lose the original class name.

test_methods

You may override this in a subclass. Currently returns all methods in a test class that start with test_ (except for the test control methods).

Please note that the behavior for include and exclude is also contained in this method. If you override it, you will need to account for those yourself.

import

Sadly, we have an import method. This is used to automatically provide you with all of the Test::Most behavior.

SAMPLE TAP OUTPUT

We use nested tests (subtests) at each level:

1..2
#
# Executing tests for TestsFor::Basic::Subclass
#
    1..3
    # TestsFor::Basic::Subclass->test_me()
        ok 1 - I overrode my parent! (TestsFor::Basic::Subclass)
        1..1
    ok 1 - test_me
    # TestsFor::Basic::Subclass->test_this_baby()
        ok 1 - This should run before my parent method (TestsFor::Basic::Subclass)
        ok 2 - whee! (TestsFor::Basic::Subclass)
        1..2
    ok 2 - test_this_baby
    # TestsFor::Basic::Subclass->test_this_should_be_run()
        ok 1 - This is test number 1 in this method
        ok 2 - This is test number 2 in this method
        ok 3 - This is test number 3 in this method
        ok 4 - This is test number 4 in this method
        ok 5 - This is test number 5 in this method
        1..5
    ok 3 - test_this_should_be_run
ok 1 - TestsFor::Basic::Subclass
#
# Executing tests for TestsFor::Basic
#
    1..2
    # TestsFor::Basic->test_me()
        ok 1 - test_me() ran (TestsFor::Basic)
        ok 2 - this is another test (TestsFor::Basic)
        1..2
    ok 1 - test_me
    # TestsFor::Basic->test_this_baby()
        ok 1 - whee! (TestsFor::Basic)
        1..1
    ok 2 - test_this_baby
ok 2 - TestsFor::Basic
# Test classes:    2
# Test methods:    5
# Total tests run: 11
ok
All tests successful.
Files=1, Tests=2,  2 wallclock secs ( 0.03 usr  0.00 sys +  0.27 cusr  0.01 csys =  0.31 CPU)
Result: PASS

REPORTING

See Test::Class::Moose::Report for more detailed information on reporting.

Reporting features are subject to change.

Sometimes you want more information about your test classes, it's time to do some reporting. Maybe you even want some tests for your reporting. If you do that, run the test suite in a subtest (because the plans will otherwise be wrong).

#!/usr/bin/env perl
use lib 'lib';
use Test::Most;
use Test::Class::Moose::Load qw(t/lib);
use Test::Class::Moose::Runner;

my $test_suite = Test::Class::Moose::Runner->new;

subtest 'run the test suite' => sub {
    $test_suite->runtests;
};
my $report = $test_suite->test_report;

foreach my $class ( $report->all_test_instances ) {
    my $class_name = $class->name;
    ok !$class->is_skipped, "$class_name was not skipped";
    ok $class->passed, "$class_name passed";

    subtest "$class_name methods" => sub {
        foreach my $method ( $class->all_test_methods ) {
            my $method_name = $method->name;
            ok $method->passed, "$method_name passed";

            ok !$method->is_skipped, "$method_name was not skipped";
            cmp_ok $method->num_tests, '>', 0,
              '... and some tests should have been run';
            diag "Run time for $method_name: ".$method->time->duration;
        }
    };
    my $time   = $class->time;
    diag "Run time for $class_name: ".$class->time->duration;

    my $real   = $time->real;
    my $user   = $time->user;
    my $system = $time->system;
    # do with these as you will
}
diag "Number of test classes: "   . $report->num_test_classes;
diag "Number of test instances: " . $report->num_test_instances;
diag "Number of test methods: "   . $report->num_test_methods;
diag "Number of tests:        "   . $report->num_tests;

done_testing;

If you just want to output reporting information, you do not need to run the test suite in a subtest:

my $test_suite = Test::Class::Moose::Runner->new->runtests;
my $report     = $test_suite->test_report;
...

Or even shorter:

my $report = Test::Class::Moose::Runner->new->runtests->test_report;

EXTRAS

If you would like Test::Class::Moose to take care of loading your classes for you, see Test::Class::Moose::Role::AutoUse in this distribution.

DEPRECATIONS AND BACKWARDS INCOMPATIBILITIES

Version 0.79

  • The Test::Class::Moose::Config class's args method is now deprecated. This was a holdover from when Test::Class::Moose was both a parent class for your test classes and the test class runner.

Version 0.77

  • The passing of the report object as an argument to test methods and test control methods is now deprecated. You can get the report from the test class object itself via the $test->test_report method.
  • The Test::Class::Moose->runtests method has been removed. Use Test::Class::Moose::Runner to run your test classes.
  • The Test::Class::Moose::Role::Parallel role has been removed. This has not done anything except issue a warning since version 0.55.

Version 0.75

  • The test_teardown method is no longer run when a test is skipped unless run_control_methods_on_skip returns a true value. The test_teardown method was never intended to be run unconditionally.
  • Parallel testing now parallelizes test classes rather than individual test instances. This is only relevant if your test suite contains parameterized test classes. This is slightly less efficient, but made the internal test running code much simpler and made it possible to fix reporting for parallel test runs.
  • The Test::Class::Moose::Config builder method has been removed.
  • The Test::Class::Moose::Runner builder method has been removed.

Version 0.67

Version 0.55

  • Running tests with Test::Class::Moose is deprecated - use Test::Class::Moose::Runner

    As of version 0.55, running tests and being a test class have been separated. Your test classes should continue to use Test::Class::Moose, but your test runner script should use Test::Class::Moose::Runner:

      use Test::Class::Moose::Load 't/lib';
      use Test::Class::Moose::Runner;
      Test::Class::Moose::Runner->new->runtests;
    

    Calling Test::Class::Moose->new->runtests still works, but is deprecated and will issue a warning.

  • Parallel testing is totally different

    The Test::Class::Moose::Role::Parallel role won't do anything other than issue a warning. See the Test::Class::Moose::Runner docs for details on running tests in parallel.

  • The Test::Class::Moose::Report all_test_classes method is deprecated

    This has been replaced with the all_test_instances method. The all_test_classes method is still present for backwards compatibility, but it simply calls all_test_instances under the hood.

  • The Test::Class::Moose::Report::Class class is gone

    It has been replaced by the Test::Class::Moose::Report::Instance class, which has the same API.

  • The Test::Class::Moose::Report::Method class_report method has been renamed

    This is now called instance_report.

Version 0.40

  • test_reporting

    As of version 0.40, the long deprecated method test_reporting has now been removed.

  • $report argument to methods deprecated

    Prior to version 0.40, you used to have a second argument to all test methods and test control methods:

      sub test_something {
          my ( $test, $report ) = @_;
          ...
      }
    

    This was annoying. It was doubly annoying in test control methods in case you forgot it:

      sub test_setup {
          my ( $test, $report ) = @_;
          $test->next::method; # oops, needed $report
          ...
      }
    

    That second argument is still passed, but it's deprecated. It's now recommended that you call the $test->test_report method to get that. Instead of this:

      sub test_froblinator {
          my ( $test, $report ) = @_;
          $report->plan(7);
          ...
      }
    

    You write this:

      sub test_froblinator {
          my $test = shift;
          $test->test_report->plan(7);
          ...
      }
    

TODO

  • Callbacks for tags (for example, 'critical' tags could bailout)
  • New test phases - start and end suite, not just start and end class/method

MORE INFO

You can find documentation for this module with the perldoc command.

perldoc Test::Class::Moose

You can also look for information at:

SEE ALSO

SUPPORT

Bugs may be submitted at https://github.com/houseabsolute/test-class-moose/issues.

I am also usually active on IRC as 'autarch' on irc://irc.perl.org.

SOURCE

The source code repository for Test-Class-Moose can be found at https://github.com/houseabsolute/test-class-moose.

AUTHORS

CONTRIBUTORS

COPYRIGHT AND LICENSE

This software is copyright (c) 2012 - 2021 by Curtis "Ovid" Poe.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.

The full text of the license can be found in the LICENSE file included with this distribution.

test-class-moose's People

Contributors

andyjack avatar autarch avatar denny avatar djgoku avatar haraldjoerg avatar jonathanstowe avatar jrubinator avatar karenetheridge avatar kwakwaversal avatar mark-5 avatar mephinet avatar n7st avatar nawglan avatar neilb avatar oalders avatar oschwald avatar pileswasp avatar preaction avatar shumphrey avatar stuckdownawell avatar tvroom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

test-class-moose's Issues

Doesn't fail on exception in control method

The following test passes for me:

package TestFor::MM::Test;

use Test::Class::Moose;

sub test_setup {
    die;
}

sub test_nothing {
    ok(1);
}

1;

It prints a diagnostic message that test_setup failed, but the test itself passes (at least when using prove):

1..1
# 
# Running tests for TestFor::MM::Test
# 
    1..1
    # TestFor::MM::Test->test_nothing()
        ok 1
        1..1
    ok 1 - test_nothing
ok 1 - TestFor::MM::Test
    # TestFor::MM::Test->test_setup() failed: Died at t/lib/TestFor/MM/Test.pm line 6.
ok
All tests successful.
Files=1, Tests=1, 10 wallclock secs ( 0.02 usr  0.00 sys +  3.84 cusr  0.84 csys =  4.70 CPU)
Result: PASS

This can lead to false passes as well as some very confusing failures.

Possible mistake in Test::Class::Moose::Tutorial

https://metacpan.org/pod/Test::Class::Moose::Tutorial#Running-Specific-Test-Classes

I think there is a mistake in the documentation.

This code does not work as expected.

# t/test_class_tests.t
use File::Spec::Functions qw( catdir );
use FindBin qw( $Bin );
use Test::Class::Moose::Load catdir( $Bin, 't', 'lib' );
use Test::Class::Moose::Runner;
Test::Class::Moose::Runner->new(
    classes => ['TestsFor::My::Test::Class'],
)->runtests;

Looking at the docs for https://metacpan.org/pod/Test::Class::Moose::Runner#CONSTRUCTOR-ATTRIBUTES, it should be

Test::Class::Moose::Runner->new(
    test_classes => ['TestsFor::My::Test::Class'],
)->runtests;

Thanks for the great project!

undef ->time

Classes and methods in Test::Class::Moose have no time associated with them if tests aren't run (such as an abstract base class). I propose that the time() methods return a default time object with time being 0 (zero) for everything. Thus, there's no need to special case reporting code to check if $class->time returns a defined value.

If a class tries to extend a Test::Class::Moose class that doesn't exist, this is silently ignored and no error is generated

Consider the following toy example, based on a bug I just hit after an incomplete refactor in our existing code base:

#!/usr/bin/env perl

use strict;
use warnings;
no warnings 'uninitialized';

use Test::Class::Moose::Runner;

package Parent {
    use Test::Class::Moose;

    sub test_startup {
        my ($self) = @_;
        $self->next::method;

        diag 'Parent class started up';
    }
    sub test_shutdown {
        my ($self) = @_;
        $self->next::method;

        diag 'Parent class shut down';
    }
}

package Sibling {
    ### FIXME: this is the bit that causes the class to vanish
    use Test::Class::Moose extends => 'Class::That::Does::Not::Exist';

    sub test_startup {
        my ($self) = @_;
        $self->next::method;

        diag 'Sibling class started up';
    }
    sub test_shutdown {
        my ($self) = @_;
        $self->next::method;

        diag 'Sibling class shut down';
    }
}

package Child {
    use Test::Class::Moose extends => 'Parent';
    use parent 'Sibling';
    sub test_startup {
        my ($self) = @_;
        $self->next::method;

        diag 'Child class started up';
    }

    sub test_shutdown {
        my ($self) = @_;
        $self->next::method;

        diag 'Child class shut down';
    }

    sub test_something {
        ok('We ran a test!');
    }
}

my $runner = Test::Class::Moose::Runner->new;
$runner->runtests;

If you run this, you get

1..2
ok 1 - Child {
    # Parent class started up
    # Child class started up
    1..1
    ok 1 - test_something {
        ok 1
        1..1
    }
    # Parent class shut down
    # Child class shut down
}
ok 2 - Parent {
    1..0 # SKIP Skipping 'Parent': no test methods found
}

If you remove the extends statement in the Sibling package, so it just says use Test::Class::Moose, you get what was intended:

1..3
ok 1 - Child {
    # Sibling class started up
    # Parent class started up
    # Child class started up
    1..1
    ok 1 - test_something {
        ok 1
        1..1
    }
    # Sibling class shut down
    # Parent class shut down
    # Child class shut down
}
ok 2 - Parent {
    1..0 # SKIP Skipping 'Parent': no test methods found
}
ok 3 - Sibling {
    1..0 # SKIP Skipping 'Sibling': no test methods found
}

I don't know what the best approach is here, whether Test::Class::Moose should squawk that Class::That::Does::Not::Exist is not a Test::Class::Moose class, or just ignore that bit and still import Test::Class::Moose, but it shouldn't silently do nothing.

use of Sub::Attribute cause strange behaviour

Hello,

I've been tracking down some strange behaviour, and although this isn't Test::Class::Moose's fault, I'm raising this here as Sub::Attribute doesn't seem to be maintained and we observed this issue in Test::Class::Moose first.

The immediate issue is when you introduce a syntax error in a Test::Class::Moose test that error can sometimes not be correctly reported.
This can be demonstrated with two test files.

# test.pl
use My::Test;
# lib/My/Test.pm
use Sub::Attributes;
sub Test : ATTR_SUB {}

sub test_other_routes1 : Test { }
sub test_other_routes2 : Test { }
sub test_other_routes3 : Test { }
sub test_other_routes4 : Test { }
sub test_other_routes5 : Test { }

sub test_that_errors : Test {
    $banana = 1;
}

1;

Running perl -c test.pl produces the error message Global symbol "$banana" requires explicit package name (did you forget to declare "my $banana"?) 32 times. (2^5 ?)
I expect that error message to only be printed once.

Running perl -c lib/My/Test.pm correctly only outputs that error message once.

Replacing the use of Sub::Attribute with native perl does not result in this error:

package My::Test;

use strict;
use warnings;

sub MODIFY_CODE_ATTRIBUTES {
    my ($class, $code, @attrs) = @_;

    return ();
}

sub test_other_routes1 : Test { }
sub test_other_routes2 : Test { }
sub test_other_routes3 : Test { }
sub test_other_routes4 : Test { }
sub test_other_routes5 : Test { }

sub test_that_errors : Test {
    $banana = 1;
}

1;

Because there seems to be some exponential component to this, with large Test::Class::Moose files we've observed linux grind to a halt with memory consumption and the process get killed.

This behaviour does not occur on older perls, e.g. perl-5.16.3

Looking at the reverse dependencies for Sub::Attribute, it is not used by many things.

Summary:
Test: perl -c test.pl
Expected: Syntax error message to be printed once
Result: Syntax error printed 32 times

Please move check for base class into a separate method

In version 0.81, the check for the TCM base class was moved into Test::Class::Moose::Role::Executor::runtests. Specifically I'm referring to this line:

https://metacpan.org/source/DROLSKY/Test-Class-Moose-0.88/lib/Test/Class/Moose/Role/Executor.pm#L45

I have a codebase where modules need to be tested in isolation, so I am using a customized parallel executor that only forks a single child process, and lazily loads each module under test. This was relatively painless to do with TCM 0.80, but since the change was introduced in 0.81 to make this base class check, I have had to copy-paste the entire runtests method into my executor in order to bypass that check, which really isn't good for maintenance in the long run. Could I ask for a minor refactor that moves this "pre-flight check" into a separate method that I can override?

Test output blocks until test class is finished

Consider the following code:

#!/usr/bin/env perl

package TestExample {
    use Test::Class::Moose;

    sub test_method {
        ok 'first';
        ok 'second';
        sleep 10;
        ok 'third';
    }
}
use Test::Class::Moose::Runner;
Test::Class::Moose::Runner->new->runtests;

That prints out:

1..1
ok 1 - TestExample {
    1..1
    ok 1 - test_method {
        ok 1
        ok 2
        ok 3
        1..3
    }
}
ok
All tests successful.
Files=1, Tests=1, 11 wallclock secs ( 0.02 usr  0.00 sys +  0.33 cusr  0.03 csys =  0.38 CPU)
Result: PASS

But I see none of that output until after the test class is completed (note the sleep 10). We have some extremely long running tests and sometimes it's nice to run them in verbose mode, but this means our tests hang and then we get a huge dump of output instead of seeing things as they go along.

Compare to this Test::More code:

#!/usr/bin/env perl

use strict;
use warnings;
use Test::More;

subtest 'TestExample' => sub {
    subtest "test_method" => sub {
        ok 'first';
        ok 'second';
        sleep 10;
        ok 'third';
    };
};
done_testing;

That prints out:

# Subtest: TestExample
    # Subtest: test_method
        ok 1
        ok 2
        ok 3
        1..3
    ok 1 - test_method
    1..1
ok 1 - TestExample
1..1
ok
All tests successful.
Files=1, Tests=1, 10 wallclock secs ( 0.02 usr  0.00 sys +  0.07 cusr  0.01 csys =  0.10 CPU)
Result: PASS

But the first output shows up before the sleep. Why is Test::Class::Moose output blocking until the end of the test class?

test_shutdown is not called when test_startup calls $self->test_skip

I'm pretty sure that this is a bug. Here's an example of why ...

At $WORK, we wrap the test_startup and test_shutdown methods to create and clear fixture data. This method wrapper kicks in before the test_startup in the class. This is necessary in case the individual class's test_startup needs the fixture data to exist.

There is a similar issue with test_setup and test_teardown, where a skipped method would not call test_teardown.

I think this should be fixed, but it probably needs a big warning in Changes, since this is backwards-incompatible change and could conceivably break someone's test suite.

@Ovid, I'd appreciate your input on this.

Can't locate object method "test_instance_name" via package

After upgrading to 0.75, I receive this error:

    Can't locate object method "test_instance_name" via package "TestForGo::MM::GeoIP2Daemon::Me=HASH(0x114a32e8)" (perhaps you forgot to load "TestForGo::MM::GeoIP2Daemon::Me=HASH(0x114a32e8)"?) at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 140.

    Trace begun at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 140
    Test::Class::Moose::Role::Executor::__ANON__('Test2::API::Context=HASH(0x1148c5d8)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Util.pm line 26
    eval {...} at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Util.pm line 25
    Test::Class::Moose::Util::context_do('CODE(0x112dace0)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 152
    Test::Class::Moose::Role::Executor::_run_test_instances('Test::Class::Moose::Executor::Sequential=HASH(0x10ca90c8)', 'TestForGo::MM::GeoIP2Daemon::Me', 'Test::Class::Moose::Report::Class=HASH(0x10c6d340)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 101
    Test::Class::Moose::Role::Executor::_run_test_class('Test::Class::Moose::Executor::Sequential=HASH(0x10ca90c8)', 'TestForGo::MM::GeoIP2Daemon::Me') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 74
    Test::Class::Moose::Role::Executor::__ANON__('Test2::AsyncSubtest=HASH(0x11360ff0)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test2/AsyncSubtest.pm line 196
    eval {...} at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test2/AsyncSubtest.pm line 196
    Test2::AsyncSubtest::run('Test2::AsyncSubtest=HASH(0x11360ff0)', 'CODE(0x10d1c5d8)', 'Test2::AsyncSubtest=HASH(0x11360ff0)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test2/Tools/AsyncSubtest.pm line 25
    Test2::Tools::AsyncSubtest::async_subtest('TestForGo::MM::GeoIP2Daemon::Me', 'HASH(0x11270c70)', 'CODE(0x10d1c5d8)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 75
    Test::Class::Moose::Role::Executor::_run_test_classes('Test::Class::Moose::Executor::Sequential=HASH(0x10ca90c8)', 'TestForGo::MM::GeoIP2Daemon::Me') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 50
    Test::Class::Moose::Role::Executor::__ANON__('Test2::API::Context=HASH(0x10ca18b0)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Util.pm line 26
    eval {...} at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Util.pm line 25
    Test::Class::Moose::Util::context_do('CODE(0x10cbf208)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 60
    Test::Class::Moose::Role::Executor::runtests('Test::Class::Moose::Executor::Sequential=HASH(0x10ca90c8)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/x86_64-linux/Moose/Meta/Method/Delegation.pm line 110
    Test::Class::Moose::Runner::runtests('Test::Class::Moose::Runner=HASH(0x10ca9068)') called at t/lib/TestHelper/TestRunner.pm line 334
    TestHelper::TestRunner::_run_tests('TestHelper::TestRunner=HASH(0xbf9bb10)') called at t/lib/TestHelper/TestRunner.pm line 123
    TestHelper::TestRunner::run('TestHelper::TestRunner=HASH(0xbf9bb10)') called at t/run-test-class-moose-1.t line 7
# Failed test 'TestForGo::MM::GeoIP2Daemon::Me'
# at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test2/Tools/AsyncSubtest.pm line 23.
Can't locate object method "builder" via package "TestHelper::MM::Test::Class::Moose::Config" at t/lib/TestHelper/TestRunner.pm line 322.

Trace begun at t/lib/TestHelper/TestRunner.pm line 322
TestHelper::TestRunner::__ANON__('Use of uninitialized value in join or string at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 52.^J') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 52
Test::Class::Moose::Role::Executor::__ANON__('Test2::API::Context=HASH(0x10ca18b0)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Util.pm line 26
eval {...} at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Util.pm line 25
Test::Class::Moose::Util::context_do('CODE(0x10cbf208)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/Test/Class/Moose/Role/Executor.pm line 60
Test::Class::Moose::Role::Executor::runtests('Test::Class::Moose::Executor::Sequential=HASH(0x10ca90c8)') called at /home/greg/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/x86_64-linux/Moose/Meta/Method/Delegation.pm line 110
Test::Class::Moose::Runner::runtests('Test::Class::Moose::Runner=HASH(0x10ca9068)') called at t/lib/TestHelper/TestRunner.pm line 334
TestHelper::TestRunner::_run_tests('TestHelper::TestRunner=HASH(0xbf9bb10)') called at t/lib/TestHelper/TestRunner.pm line 123
TestHelper::TestRunner::run('TestHelper::TestRunner=HASH(0xbf9bb10)') called at t/run-test-class-moose-1.t line 7
Use of uninitialized value $StartedInPid in numeric eq (==) at t/lib/MM/Test/Redis.pm line 98.
# IPC is waiting for children to finish...
# Looks like your test exited with 255 just after 1.

TCM roles are not handled correctly when there are tags to exclude

When tags and TCM roles are used, the following exception is issued by the script:

$ prove -vm tcm.t 
tcm.t .. 
1..1
not ok 1 - TestsFor::SomeClass {
    # TestsFor::SomeClass::Role1|TestsFor::SomeClass::Role2 is not a module name at /Users/ichesnokov/.perlbrew/libs/perl-5.30.1@test/lib/perl5/darwin-2level/Class/MOP/Package.pm line 218.
    1..0
}

See the attached code for an example.
tcm-case.zip

TODO test regression starting in .72

Starting in TCM .72, $builder->todo_start tests are now failing if an exception is thrown. Prior to .72, those tests would pass even if an exception was thrown. Now they don't. Switching to TODO {...} causes them to fail even prior to .72. This is probably a Test2 issue, but I'm unsure. In any event, you may have other consumers of TCM who are impacted.

I've attached a zip file (github apparently doesn't like tarballs). It extracts a minimal test case into a tcm_error/ directory. cd into that directory and run ./show_failure. That will force install TCM .71 and run the test. Then it will force install .72 and rerun the tests. The TODO test fails on .72 and beyond.

Obviously, you probably want to run this on an isolated Perl install :)

tcm_error.zip

Better support running subsets of tests

While using Test::Class::Moose, I realized that the arguments to Test::Class::Moose::Load are not just directories, but roots of libraries - they expect the underlying path structure to match package names. This prevents running only a subset of the test directory, because we run into namespace-collisions:

[12:57]$ cat t/runtests.t
use strict;
use warnings;

use Test::Class::Moose::Runner;
use Test::Class::Moose::Load 't/Test/Custom';

Test::Class::Moose::Runner->new->runtests;
[12:57]$ cat t/Test/Custom/Importer.pm
package Test::Custom::Importer;

use Test::Class::Moose;

sub test_ok :Test {
    unlike $INC{'Importer.pm'},
           qr{Test/Custom},
           "`require Importer` won't use this file";
}

1;
[12:57]$ prove t/runtests.t
t/runtests.t .. 1/1         #   Failed test '`require Importer` won't use this file'
        #   at t/Test/Custom/Importer.pm line 6.
        #                   't/Test/Custom/Importer.pm'
        #           matches '(?^:Test/Custom)'
    # Failed test 'test_ok'
...

How would we feel about enhancing Test::Class::Moose::Load to support something like the following:

use Test::Class::Moose::Load
    -libs => [ qw(t/tests) ],
    -dirs => [ qw(t/tests/this t/tests/that) ], # but not t/tests/the_other
;

I think the old use-line use Test::Class::Moose::Load @libs would be equivalent to the following (and we could continue to support it):

use Test::Class::Moose::Load -libs => \@libs, -dirs => \@libs;
# or to
use Test::Class::Moose::Load -libs => \@libs;

Segmentation fault at global destruction time caused by subroutine attributes?

We have a fairly hefty test suite at $WORK. It uses Test::Class::Moose, and because it originally used Test::Class, a lot of the test methods are declared as e.g. sub valid :Tests { ... }

Recently a lot of our Jenkins builds have been segfaulting at global destruction time: all tests pass, but the process ends with a non-zero exit status 11. This has been intermittent, but I think I've narrowed down a test case where it nearly always happens. I have yet to work out whether this is Test::Class::Moose to blame, or something else (Sub::Attribute?), but I thought I'd dump what I had for now.

The test is remarkably straightforward:

package Foo;

use Test::Class::Moose;

sub a : Tests {}
sub b : Tests {}
sub c : Tests {}
sub d : Tests {}
sub e : Tests {}
sub f : Tests {}
sub g : Tests {}

1;
sam@chimera:tmp$ perl -c -I. -MFoo -e0

That produces a variety of errors depending on the exact circumstance. Notably, if I comment out any one of the sub definitions, or remove the :Tests attribute from any one of them, the class compiles happily. I'll attach full details as the first comment on this issue.

Attribute override in TCM-using child class results in tests being ignored

Code and test output can be found at https://gist.github.com/genehack/4a9c0979881ab5bd25ea.

Basically, I have a 'Base::Foo' class that uses plain Moose, and defines a required attribute called 'foo'. I also have a 'Tests::Bar' class that uses TCM, extends 'Base::Foo', and does has "+foo" => ( default => "baz" ). Using the standard test runner from the documentation, that results in a '0 tests run' output.

One workaround is to make 'Tests::Bar' do extends 'Test::Class::Moose', 'Base::Foo';. That's sort of ... nasty.

Another workaround is to make Base::Foo a role (using Moose::Role) and have Tests::Bar consume it. That would be acceptable (and maybe even arguably better), but this still seems like something that should either work (because it's just standard Moose crap), or be documented as not working.

Failed test control methods do not stop testing of class

The documentation states, " If a test control method fails, the class/method will fail and testing for that class should stop." However, testing for the class does not stop. I believe this used to be the case, but it doesn't seem to be anymore.

Example:

package TestsFor::Fail;

use Test::Class::Moose;
use Throwable::Error;

sub test_setup {
    fail();
}

sub test_ok {
    ok(1);
}

package main;

use Test::Class::Moose::CLI;
Test::Class::Moose::CLI->new_with_options->run;

Output:

1..1
not ok 1 - TestsFor::Fail {
    1..1
    not ok 1
    #   Failed test at /home/greg/.plenv/versions/5.28.2/lib/perl5/site_perl/5.28.2/Test/Class/Moose/Role/Executor.pm line 168.
    not ok 2 - TestsFor::Fail->test_setup failed
    # Failed test 'TestsFor::Fail->test_setup failed'
    # at /home/greg/.plenv/versions/5.28.2/lib/perl5/site_perl/5.28.2/Test/Class/Moose/Role/Executor.pm line 168.
    # Tests may not be run in test control methods (test_setup) at /home/greg/.plenv/versions/5.28.2/lib/perl5/site_perl/5.28.2/Test/Class/Moose/Role/Executor.pm line 411.
    ok 3 - test_ok {
        ok 1
        1..1
    }
}

# Failed test 'TestsFor::Fail'
# at /home/greg/.plenv/versions/5.28.2/lib/perl5/site_perl/5.28.2/Test2/Tools/AsyncSubtest.pm line 23.
# IPC is waiting for children to finish...
# Looks like you failed 1 test of 1.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests 

Test Summary Report
-------------------
test.t (Wstat: 256 Tests: 1 Failed: 1)
  Failed test:  1
  Non-zero exit status: 1
Files=1, Tests=1,  1 wallclock secs ( 0.01 usr  0.00 sys +  0.40 cusr  0.04 csys =  0.45 CPU)
Result: FAIL

As you can see, the test_ok method is still run. We use the test control methods to set up our fixtures, and this issue can result in a lot of unnecessary noise when the fixture setup fails.

Can't locate object method "class" via package "Test::Class::Moose::Report::Instance" at Test/Class/Moose/Report/Method.pm line 57

Hello, Thanks for Test::Class::Moose. I recently took on a legacy code base with a much neglected test suite, so took the opportunity to effectively start over and rebuild using Test::Class::Moose and I've been finding it both usable and useful.

Today I wanted to do some different things in test_setup depending on the tags on the test, so I used the documentation, but the example provided dies:

Full minimal example:

use Test::Class::Moose::Runner;

Test::Class::Moose::Runner->new( test_classes => ['Tag::Test'] )->runtests;

package Tag::Test;

use Test::Class::Moose;

sub test_setup {
    my $test = shift;

    my $method_to_run = $test->test_report->current_method;
    if ( $method_to_run->has_tag('db') ) {
        warn "Do db things";
    }
    else {
        warn "Do something else";
    }
}

sub test_the_db : Tags( db ) {
    ok 1, "test_the_db";
}

sub test_not_the_db {
    ok 1, "not the db";
}

Output:

$ prove TCM_test.pl
TCM_test.pl .. 1/1     # Failed test 'Tag::Test->test_setup failed'
    # at /usr/local/share/perl/5.22.1/Test/Class/Moose/Role/Executor.pm line 168.
    # Can't locate object method "class" via package "Test::Class::Moose::Report::Instance" at /usr/local/share/perl/5.22.1/Test/Class/Moose/Report/Method.pm line 57.
    # Failed test 'Tag::Test->test_setup failed'
    # at /usr/local/share/perl/5.22.1/Test/Class/Moose/Role/Executor.pm line 168.
    # Can't locate object method "class" via package "Test::Class::Moose::Report::Instance" at /usr/local/share/perl/5.22.1/Test/Class/Moose/Report/Method.pm line 57.

# Failed test 'Tag::Test'
# at /usr/local/share/perl/5.22.1/Test2/Tools/AsyncSubtest.pm line 23.
# Looks like you failed 1 test of 1.
TCM_test.pl .. Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests

Test Summary Report
-------------------
TCM_test.pl (Wstat: 256 Tests: 1 Failed: 1)
  Failed test:  1
  Non-zero exit status: 1
Files=1, Tests=1,  1 wallclock secs ( 0.03 usr  0.00 sys +  0.53 cusr  0.02 csys =  0.58 CPU)
Result: FAIL

This is true for both version 0.98 and 0.99 on perl v5.22.1 and v5.30.0.

The fix seems simple enough (pull request incoming), but without digging deeper into the Test::Class::Moose testsuite, I'm not sure why it's not already caught. A cursory reading suggests test_me() in t/taglib/TestsFor/Basic.pm ought to catch it (and does, if you run it explicitly), but it appears it might be a "meta" test that is not actually run.

Perhaps someone else can figure that one out more readily than me.

Test classes with compilation errors pass

This is Test::Class::Moose version 0.91.

On a number of occasions we've found that our test classes have a syntax error and are skipped, but the test passes. Below is an example:

#!/usr/bin/env perl

use strict;
use warnings;

use Test::Class::Moose::Runner;

eval <<'END_CLASS';
package BadClass {
    use Test::Class::Moose;

    sub test_something {
        ok $undeclared_variable, 'You shall not pass';
    }
}
END_CLASS
eval <<'END_CLASS';
package GoodClass {
    use Test::Class::Moose;

    sub test_something_else {
        ok 1, 'OK, you can pass';
    }
}
END_CLASS

my $runner = Test::Class::Moose::Runner->new;
$runner->runtests;

And when you run that:

tcm.t ..
1..2
ok 1 - BadClass {
    1..0 # SKIP Skipping 'BadClass': no test methods found
}
ok 2 - GoodClass {
    1..1
    ok 1 - test_something_else {
        ok 1 - OK, you can pass
        1..1
    }
}
ok
All tests successful.
Files=1, Tests=2,  1 wallclock secs ( 0.01 usr  0.00 sys +  0.25 cusr  0.02 csys =  0.28 CPU)
Result: PASS

I suspect this may have the same underlying issue as #70.

No elapsed time recorded in 0.85

Running this test

# t/tests/TestFor/Sleep.pm
package TestFor::Sleep;
use Test::Class::Moose;

sub test_sleep {
    my $test = shift;
    sleep 5;
    is 1, 1, "Yes!";
}

1;

with this loader

# t/loader.t
use strict;
use warnings;

use Test::Class::Moose::Load 't/tests';
use Test::Class::Moose::Runner;
use Data::Dumper;

my $runner = Test::Class::Moose::Runner->new;

$runner->runtests;
my $rep = $runner->test_report;
print Dumper($rep);

gives this output with 0.85

$VAR1 = bless(
  { 'test_classes' => [
      bless(
        { 'start_time' => '1504601210.77945',
          '_end_benchmark' =>
           bless( ['1504601210.77943', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
          'notes'          => {},
          'name'           => 'TestFor::Sleep',
          'test_instances' => [
            bless(
              { '_start_benchmark' =>
                 bless( ['1504601210.77974', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                'test_shutdown_method' => bless(
                  { 'instance' => $VAR1->{'test_classes'}[0]{'test_instances'}[0],
                    '_end_benchmark' =>
                     bless( ['1504601215.78519', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                    'num_tests_run' => 0,
                    'start_time'    => '1504601215.7852',
                    '_start_benchmark' =>
                     bless( ['1504601215.7852', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                    'notes'    => {},
                    'name'     => 'test_shutdown',
                    'end_time' => '1504601215.78519',
                    'passed'   => 0
                  },
                  'Test::Class::Moose::Report::Method'
                ),
                'passed'              => 1,
                'end_time'            => '1504601210.77971',
                'name'                => 'TestFor::Sleep',
                'notes'               => {},
                'test_startup_method' => bless(
                  { 'notes'    => {},
                    'name'     => 'test_startup',
                    'end_time' => '1504601210.78053',
                    'passed'   => 0,
                    '_start_benchmark' =>
                     bless( ['1504601210.78056', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                    'num_tests_run' => 0,
                    'start_time'    => '1504601210.78056',
                    'instance'      => $VAR1->{'test_classes'}[0]{'test_instances'}[0],
                    '_end_benchmark' =>
                     bless( ['1504601210.78053', '0.28', '0.04', '0', '0', 0], 'Benchmark' )
                  },
                  'Test::Class::Moose::Report::Method'
                ),
                '_end_benchmark' =>
                 bless( ['1504601210.77971', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                'start_time'   => '1504601210.77974',
                'test_methods' => [
                  bless(
                    { 'start_time'           => '1504601210.78071',
                      'tests_planned'        => 1,
                      'num_tests_run'        => 1,
                      'test_teardown_method' => bless(
                        { 'passed'   => 0,
                          'end_time' => '1504601215.78501',
                          'name'     => 'test_teardown',
                          'notes'    => {},
                          '_start_benchmark' =>
                           bless( ['1504601215.78505', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                          'start_time'    => '1504601215.78505',
                          'num_tests_run' => 0,
                          '_end_benchmark' =>
                           bless( ['1504601215.78501', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                          'instance' => $VAR1->{'test_classes'}[0]{'test_instances'}[0]
                        },
                        'Test::Class::Moose::Report::Method'
                      ),
                      '_end_benchmark' =>
                       bless( ['1504601210.7807', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                      'instance'          => $VAR1->{'test_classes'}[0]{'test_instances'}[0],
                      'passed'            => 1,
                      'test_setup_method' => bless(
                        { 'num_tests_run' => 0,
                          'start_time'    => '1504601210.78074',
                          'instance'      => $VAR1->{'test_classes'}[0]{'test_instances'}[0],
                          '_end_benchmark' =>
                           bless( ['1504601210.78073', '0.28', '0.04', '0', '0', 0], 'Benchmark' ),
                          'notes'    => {},
                          'name'     => 'test_setup',
                          'end_time' => '1504601210.78073',
                          'passed'   => 0,
                          '_start_benchmark' =>
                           bless( ['1504601210.78074', '0.28', '0.04', '0', '0', 0], 'Benchmark' )
                        },
                        'Test::Class::Moose::Report::Method'
                      ),
                      'end_time' => '1504601210.7807',
                      'name'     => 'test_sleep',
                      'notes'    => {},
                      '_start_benchmark' =>
                       bless( ['1504601210.78071', '0.28', '0.04', '0', '0', 0], 'Benchmark' )
                    },
                    'Test::Class::Moose::Report::Method'
                  )
                ]
              },
              'Test::Class::Moose::Report::Instance'
            )
          ],
          'end_time' => '1504601210.77943',
          'passed'   => 1,
          '_start_benchmark' =>
           bless( ['1504601210.77945', '0.28', '0.04', '0', '0', 0], 'Benchmark' )
        },
        'Test::Class::Moose::Report::Class'
      )
    ],
    'end_time'    => '1504601210.77847',
    'start_time'  => '1504601210.77851',
    'is_parallel' => 0,
    '_end_benchmark' =>
     bless( ['1504601210.77847', '0.27', '0.04', '0', '0', 0], 'Benchmark' ),
    '_start_benchmark' =>
     bless( ['1504601210.77851', '0.27', '0.04', '0', '0', 0], 'Benchmark' )
  },
  'Test::Class::Moose::Report'
);

Although the test case takes 5 seconds to run, start_time and end_time are nearly identical:

'start_time' => '1504601210.78071',
'end_time' => '1504601210.7807',

Reverting to 0.84 makes the problem go away.

is there a method for doing chained tests?

I'm not sure it is appropriate to ask questions here, please let me know if you'd like me to move this somewhere else. I appreciate any feedback you have.

I am working on system testing a few command-line programs where the input of one depends on the output of another. This appears to be called 'chained testing':

http://xunitpatterns.com/Chained%20Tests.html

I was wondering if there was a method of doing this with Test::Class::Moose? I was not able to find anything going through the documentation and some source.

Here is an example of something similar with phpunit:

https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.test-dependencies

Can't access name of "run" from within class

Test::Class::Moose doesn't expose the internal name of a run to the run instance itself.

I'm working on a role that creates named directories for each test run. For classes that have a one-to-one mapping of class to run this is trivial, but at for classes that produce multiple runs per class file (e.g. parameterized classes) I can't get a unique name for the test run because TCM doesn't expose the internal name it uses.

Can't locate object method "_tcm_make_test_class_instances" and/or skipped tests

Hi

I'm working on a team which is developing a Moose based app which uses Test::Class::Moose as the testing framework. We're seeing a very generic error message returned, or in some cases skipped tests completely, if there is a syntax error in the test class and/or file being tested. After speaking to @Ovid, raising here as an issue here.

The replication steps below may not be exhaustive but hopefully highlight the issues.

Can't locate object method "_tcm_make_test_class_instances"

This occurs when there is a compilation error in the test file itself, in this case a missing semi-colon in the test class file.

t/20-units/run_class.t ..
1..1
#
# Running tests for Test::XXX
#
    # Subtest: Test::XXX
Can't locate object method "_tcm_make_test_class_instances" via package "Test::XXX" (perhaps you forgot to load "Test::XXX"?) at /opt/xt/xt-perl/lib/site_perl/Test/Class/Moose/Role/Executor.pm line 52.
END failed--call queue aborted.
# Looks like your test exited with 22 before it could output anything.
Dubious, test returned 22 (wstat 5632, 0x1600)
Failed 1/1 subtests

Test Summary Report
-------------------
t/20-units/run_class.t (Wstat: 5632 Tests: 0 Failed: 0)
  Non-zero exit status: 22
  Parse errors: Bad plan.  You planned 1 tests but ran 0.
Files=1, Tests=0,  5 wallclock secs ( 0.03 usr  0.01 sys +  4.81 cusr  0.16 csys =  5.01 CPU)
Result: FAIL

Skipped tests (no test methods found)

The second issue occurs when there is a syntax issue with the file being tested, in this case a missing semi-colon. This one is problematic as the tests come back as PASS and if you aren't running in verbose mode if can be easily overlooked.

t/20-units/run_class.t ..
1..1
#
# Running tests for Test::XXX
#
    # Subtest: Test::XXX
    1..0 # SKIP Skipping 'Test::XXX': no test methods found
ok 1 # skip Skipping 'Test::XXX': no test methods found
# Test instances:  1
# Test methods:    0
# Total tests run: 0
ok
All tests successful.
Files=1, Tests=1,  3 wallclock secs ( 0.03 usr  0.01 sys +  2.27 cusr  0.23 csys =  2.54 CPU)
Result: PASS

If you need anymore information just let me know.

Attaching @Ovid's quote for reference:

The issue you're describing came up when TCM was refactored to allow instances of test classes (allowing you to run a test class in different contexts) and I've seen in a couple of times myself. I keep forgetting to resolve it. I suspect it's an unchecked eval. Could you open an issue in our repo so both Dave and I are notified?

Thanks

Andy

Test runner application

I think it'd be good idea to include a test runner for Test::Class::Moose as an application, something like prove_class t/testlib. It could accept all the Test::Class::Moose attributes as options, and it would make it easier to run Test::Class::Moose classes with all the options.

In a perfect world, we'd extend App::Prove to be able to handle test classes, but the ideas I'm coming up with for how to handle it aren't very good.

Test::Class::Moose::Report->num_tests_run causing undef warning

If there are no tests run, Test::Class::Moose::Report->num_tests_run returns undef because it's using List::Util::num instead of List::Util::num0.

An undef warning is then emitted at Test/Class/Moose/Role/Executor.pm line 66 where the undef from num_tests_run is interpolated in Test::Class::Moose::Role::Executor->runtests.

Test::Kit integration

When I wrote Test::Class::Moose, I made a design decision that I currently regret. Specifically, Test::Most is automatically provided. However, it's showing its age. Test::Kit would have been a better choice, but I had never gotten around to fixing some core issues in the latter.

Recently, Alex Balhatchet has taken over Test::Kit and it's now a much more flexible testing system. By determining how to combine the two, we can offer users the power of Test::Class::Moose, but using a set of their own test modules rather than whatever I thought to include in Test::Most.

Use of qw(...) as parentheses is deprecated

When running in 5.16.1 with warnings on the following warning is produced:

Use of qw(...) as parentheses is deprecated at test-class-moose/lib/Test/Class/Moose/Role/Reporting.pm line 37.

Moose error can happen because of order in which roles are consumed

user@host:~/app$ cat t/suite.t
use warnings;
use File::Spec::Functions qw( catdir );
use FindBin qw( $Bin );
use Test::Class::Moose::Load catdir( $Bin, 'lib/' );
use Test::Class::Moose::Runner;
Test::Class::Moose::Runner->new->runtests;

user@host:~/app$ cat t/lib/A.pm
package t::A;
use Test::Class::Moose;
with qw/t::Role/;

BEGIN { print "IN A\n";}

sub test_hey {
    ok 1, "hello";
}

1;

user@host:~/app$ cat t/lib/Role.pm
package t::Role;
use Test::Class::Moose::Role;

BEGIN { print "IN ROLE\n";}

sub test_role {
    ok 1, "from role";
}

1;

user@host:~/app$ prove -v t/suite.t
t/suite.t ..
IN A
You can only consume roles, t::Role is not a Moose role at /usr/local/lib/x86_64-linux-gnu/perl/5.20.2/Moose/Exporter.pm line 419
        Moose::with('t::Role') called at /home/user/app/t/lib/A.pm line 4 
        require A.pm at (eval 7) line 1
        Test::Class::Moose::Load::BEGIN at /home/user/app/t/lib/A.pm line 0 
        eval {...} at /home/user/app/t/lib/A.pm line 0 
        eval 'use A ()' at /usr/local/share/perl/5.20.2/Test/Class/Moose/Load.pm line 54
        Test::Class::Moose::Load::_load('Test::Class::Moose::Load', '/home/user/app/t/lib/A.pm', '/home/user/app/t/lib') called at /usr/local/share/perl/5.20.2/Test/Class/Moose/Load.pm line 68
        Test::Class::Moose::Load::__ANON__ at /usr/share/perl/5.20/File/Find.pm line 796
        File::Find::_find_dir('HASH(0x1e4fb50)', '/home/user/app/t/lib', 3) called at /usr/share/perl/5.20/File/Find.pm line 578
        File::Find::_find_opt('HASH(0x1e4fb50)', '/home/user/app/t/lib') called at /usr/share/perl/5.20/File/Find.pm line 1081
        File::Find::find('HASH(0x1e4fb50)', '/home/user/app/t/lib') called at /usr/local/share/perl/5.20.2/Test/Class/Moose/Load.pm line 73
        Test::Class::Moose::Load::import('Test::Class::Moose::Load', '/home/user/app/t/lib') called at t/suite.t line 6 
        main::BEGIN at /home/user/app/t/lib/A.pm line 0 
        eval {...} at /home/user/app/t/lib/A.pm line 0 
Compilation failed in require at (eval 7) line 1.
BEGIN failed--compilation aborted at (eval 7) line 1.
BEGIN failed--compilation aborted at t/suite.t line 6.
Dubious, test returned 255 (wstat 65280, 0xff00)
No subtests run

Test Summary Report
-------------------
t/suite.t (Wstat: 65280 Tests: 0 Failed: 0)
  Non-zero exit status: 255
  Parse errors: No plan found in TAP output
Files=1, Tests=0,  0 wallclock secs ( 0.03 usr  0.00 sys +  0.39 cusr  0.03 csys =  0.45 CPU)
Result: FAIL

user@host:~/app$ mv t/lib/A.pm t/lib/subdir/
user@host:~/app$ prove -v t/suite.t
t/suite.t ..
IN ROLE
IN A
1..1
ok 1 - t::A {
    1..2
    ok 1 - test_hey {
        ok 1 - hello
        1..1
    }
    ok 2 - test_role {
        ok 1 - from role
        1..1
    }
}
ok
All tests successful.
Files=1, Tests=1,  0 wallclock secs ( 0.03 usr  0.01 sys +  0.66 cusr  0.01 csys =  0.71 CPU)
Result: PASS

There is a similar issue with test class inheritance where the child class must be loaded after the parent by forcing it into a subdirectory (found by adding debug statements in Test::Class::Moose::Load::import).

Regardless, very nice framework.

Can not skip test class with test_skip method

Hi, I have a question about 'is_skipped()' method.

I make some class and then wrote test code that have skip test. (naturally, in the startup method)

but after run $test_suite->runtests and run $report->all_test_classes, checking skipped test class(is_skipped()) was not working right.

Code

...

use Test::Class::Moose::Load abs_path(dirname $0) . '/t/lib';

...

### MyTest is parent class of the Test::Sample1, Test::Sample2 
my $test_suite = Test::MyTest->new(
    test_classes => ['Test::Sample1', 'Test::Sample2']
);

...

subtest 'UnitTest Suite' => sub
{
    $test_suite->runtests;
};

my $report = $test_suite->test_report;

for my $class ($report->all_test_classes)
{
    my $class_name = $class->name;

    ok (!$class->is_skipped, "$class_name was not skipped");

Output

ok 3 - Test::Sample1 methods
# Run-time for Test::Sample1: 0.044265 wallclock secs ( 0.04 usr +  0.00 sys =  0.04 CPU)
not ok 4 - Test::Sample2 was not skipped
#   Failed test 'Test::Sample2 was not skipped'
#   at UnitTest line 74.
    # Subtest: Test::Sample2 methods
    1..0
    # No tests run!
not ok 5 - No tests run for subtest "Test::Sample2 methods"
#   Failed test 'No tests run for subtest "Test::Sample2 methods"'
#   at UnitTest line 89.
Can't call method "duration" on an undefined value at UnitTest line 92.
# Tests were run but no plan was declared and done_testing() was not seen.
# Looks like your test exited with 29 just after 5.

Using MooseX::StrictConstructor in a test class breaks >= 0.77

If any Test::Class::Moose test role uses MooseX::StrictConstructor, that role gets applied to Test::Class::Moose as well. This results in an exception, because Role::Executor::_run_test_instances is still passing the old config options to Test::Class::Moose->new, but as of commit 12d14a0 these options are no longer being stripped in Test::Class::Moose::BUILDARGS.

tcm-strictconstructor-bug.pl.txt
tcm-strictconstructor-bug.pl.out.txt

As an aside, I wonder if there are other MooseX roles that could be applied to TCM roles that could break the TCM core...

Errors if a class has no test_ methods

If a class has no test methods (eg a base class containing setup methods) errors are thrown and testing bails out when running tests:

prove -lv --merge t/run.t 
t/run.t .. 
1..2
# 
# Executing tests for My::Test::Class
# 
Use of uninitialized value in string eq at /Users/tomberesford/perl5/perlbrew/perls/5.16.1_THREADS_DEBUGGING/lib/5.16.1/Test/More.pm line 1240.
skip() needs to know $how_many tests are in the block at /Users/tomberesford/Dropbox/perl_snippets/TestClassMoose/test-class-moose/lib/Test/Class/Moose.pm line 182
    ok 1 # skip Skipping 'My::Test::Class': no test methods found
Label not found for "last SKIP" at /Users/tomberesford/perl5/perlbrew/perls/5.16.1_THREADS_DEBUGGING/lib/5.16.1/Test/More.pm line 1256.
# Looks like your test exited with 29 before it could output anything.
Dubious, test returned 29 (wstat 7424, 0x1d00)
Failed 2/2 subtests 

adding any test method to base test class allows test suite to run, eg

sub test_me {ok(1, 'ok')}

Expose test failures through report

I'd like to get a summary of all the classes that have test failures at the end of a report. I see each class exposes has_error, but this seems to be for compilation errors. Instead, I'd like a method like has_failure. Example usage:

my $test_suite = Test::Class::Moose->new(
  test_classes => \@ARGV,
  randomize   => 0,
  show_timing => 1,
  statistics  => 1,
);

$test_suite->runtests;
my $report = $test_suite->test_report;

my @skipped_tests = grep { $_->is_skipped } $report->all_test_classes;
my @failed_tests = grep { $_->has_failure } $report->all_test_classes;

diag "Skipped ${\$_->name} : ${\$_->skipped}" for @skipped_tests;
diag "Failed ${\$_->name}" for @failed_tests;

Output of subtests is not shown v0.78

Example:

t/class.t

use Test::Class::Moose::Load qw(lib);
use Test::Class::Moose::Runner;
Test::Class::Moose::Runner->new->runtests;

t/lib/MyTest.pm

package MyTest;
use Test::Class::Moose;

sub test_subtest {
    pass('test 1');
    subtest 'subtest - not shown' => sub {
        # Output of these tests is not shown...
        pass 'test 2';
        pass 'test 3';
        pass 'test 4';
    };
    pass('test 5');
}

1;

Output

$ prove -vm class.t 
class.t .. 
1..1
ok 1 - MyTest {
    1..1
    ok 1 - test_subtest {
        ok 1 - test 1
        # Subtest: subtest - not shown
        ok 2 - subtest - not shown
        ok 3 - test 5
        1..3
    }
}
ok
All tests successful.
Files=1, Tests=1,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.37 cusr  0.03 csys =  0.42 CPU)
Result: PASS

As you can see, results for 'test 2', 'test 3' and 'test 4' are missing in output.

moose attributes not being applied?

package TestsFor::MehMeh;
use Test::Class::Moose;


has 'test_fixture' => ( is => 'rw' );
sub test_setup {
    my $test = shift;
    $test->test_fixture("sdasdasd");
    #####STARTDEBUG
    do {
    use Data::Printer output => 'stderr',colored =>1, deparse => 1, caller_info => 1, show_readonly => 1, show_lvalue => 1, class => { inherited => 'all' };
    p $test->meta->get_all_attributes;
    };

    #####ENDDEBUG

}

sub test_this_is_a_method {
    my $test = shift;
    ok 1, 'whee!';
}


1;

use Test::Class::Moose::Runner;
INIT { Test::Class::Moose::Runner->new->runtests } # here's the magic!

and the output

1..1
#
# Running tests for TestsFor::MehMeh
#
    # Subtest: TestsFor::MehMeh
    1..1
    # TestsFor::MehMeh->test_setup() failed: Can't locate object method "test_fixture" via package "TestsFor::MehMeh" at m3h.pl line 8.
    not ok 1 - test_setup failed
    #   Failed test 'test_setup failed'
    #   at /Users/***/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/Test/Class/Moose/Role/Executor.pm line 273.
    # TestsFor::MehMeh->test_this_is_a_method()
        # Subtest: test_this_is_a_method
        ok 1 - whee!
        1..1
    ok 2 - test_this_is_a_method
    # Looks like you planned 1 test but ran 2.
    # Looks like you failed 1 test of 2 run.
not ok 1 - TestsFor::MehMeh
#   Failed test 'TestsFor::MehMeh'
#   at /Users/****/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/darwin-thread-multi-2level/Moose/Meta/Method/Delegation.pm line 110.

Allow instantiation of a given test class multiple times with different parameters

Several times now I've found myself wanting to write a test class which runs essentially the same tests but with different sets of parameters.

As it stands now I'd either need to make these separate classes (where the parameter defaults differ but everything else is shared in a role), or simply put the tests in a helper object that the test class creates. I've opted for the latter, but I don't really like it.

One solution I thought of was simply to add some sort of method to returns an array of constructor params:

package TestFor::ThingWithOptionalCache;

sub test_parameter_sets {
    return( { use_cache => 1 }, { use_cache => 0 } );
}

Then Test::Class::Moose would check for this and create multiple TestFor::ThingWithOptionalCache objects and run the tests against them.

Of course, then we come to an issue of how the subtests are named and you might want to require that each object implement a subtest_suffix() method too.

Anyway, this is just a vague idea, but I suspect other people would have a similar need. Maybe there is a better way to solve this problem that I'm not seeing?

Test-Class-Moose-0.68 no longer exports Test::Most functions into subclasses

The gist https://gist.github.com/mephinet/e15b01d6241f40f0f34c9cbaae35ea1d reproduces an issue we face since updating T:C:M to 0.68:
We have a class 'P', which uses T:C:M, and a subclass 'C' that extends 'P'. Within P, we use ok. In 0.67, this worked fine. In 0.68, we get:

    #   Failed test 'test_something failed: Undefined subroutine &Test_Child::ok called at tcm2.pl line 12.

Reverting to 0.67 fixes the issue. This could be related to 05e0373.

Test output gets swallowed when --jobs > 1

Not sure if the issue is with Test::Class::Moose, but I thought this would be a good starting point. I took @oschwald's demonstration of the issue and created a git repo to make it easier to replicate.

git clone https://github.com/oalders/test-jobs-behaviour
cd test-jobs-behaviour
prove -v --jobs 1 t/runner.t
prove -v --jobs 2 t/runner.t

Output should be similar to:

$ prove -v --jobs 1 t/runner.t
t/runner.t ..
1..1
not ok 1 - TestsFor::DateTime {
    1..1
    not ok 1 - test_constructor {
        not ok 1
        ok 2 - DateTime->can('new')
        ok 3 - An object of class 'DateTime' isa 'DateTime'
        ok 4 - ... and the year should be correct
        1..4
    }
}
        #   Failed test at t/lib/TestFor/DateTime.pm line 10.
    # Failed test 'test_constructor'
    # at /Users/olafalders/.plenv/versions/5.30.3/lib/perl5/site_perl/5.30.3/Test2/Tools/AsyncSubtest.pm line 23.

# Failed test 'TestsFor::DateTime'
# at /Users/olafalders/.plenv/versions/5.30.3/lib/perl5/site_perl/5.30.3/Test2/Tools/AsyncSubtest.pm line 23.
# IPC is waiting for children to finish...
# Looks like you failed 1 test of 1.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests

Test Summary Report
-------------------
t/runner.t (Wstat: 256 Tests: 1 Failed: 1)
  Failed test:  1
  Non-zero exit status: 1
Files=1, Tests=1,  1 wallclock secs ( 0.02 usr  0.01 sys +  0.74 cusr  0.10 csys =  0.87 CPU)
Result: FAIL

$ prove -v --jobs 2 t/runner.t

not ok 1 - TestsFor::DateTime {
        #   Failed test at t/lib/TestFor/DateTime.pm line 10.
    # Failed test 'test_constructor'
    # at /Users/olafalders/.plenv/versions/5.30.3/lib/perl5/site_perl/5.30.3/Test2/Tools/AsyncSubtest.pm line 23.

# Failed test 'TestsFor::DateTime'
# at /Users/olafalders/.plenv/versions/5.30.3/lib/perl5/site_perl/5.30.3/Test2/Tools/AsyncSubtest.pm line 23.
# Looks like you failed 1 test of 1.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests

Test Summary Report
-------------------
t/runner.t (Wstat: 256 Tests: 1 Failed: 1)
  Failed test:  1
  Non-zero exit status: 1
Files=1, Tests=1,  1 wallclock secs ( 0.02 usr  0.01 sys +  0.51 cusr  0.05 csys =  0.59 CPU)
Result: FAIL

It looks like having more than 1 test jobs creates the problem.

Can't locate Fail.pm

Running on Mac OS X 10.10 with Perl 5.16 I get Can't locate Fail.pm when trying to install this module. Here's the complete output:

cpanm (App::cpanminus) 1.6921 on perl 5.016002 built for darwin-2level
Work directory is /Users/jt/.cpanm/work/1435019167.26494
You have make /usr/bin/make
You have LWP 6.05
You have /usr/bin/tar: bsdtar 2.8.3 - libarchive 2.8.3
You have /usr/bin/unzip
Searching Test::Class::Moose on cpanmetadb ...
--> Working on Test::Class::Moose
Fetching http://www.cpan.org/authors/id/O/OV/OVID/Test-Class-Moose-0.58.tar.gz ... OK
Unpacking Test-Class-Moose-0.58.tar.gz
x Test-Class-Moose-0.58/
x Test-Class-Moose-0.58/Changes
x Test-Class-Moose-0.58/dist.ini
x Test-Class-Moose-0.58/lib/
x Test-Class-Moose-0.58/LICENSE
x Test-Class-Moose-0.58/Makefile.PL
x Test-Class-Moose-0.58/MANIFEST
x Test-Class-Moose-0.58/META.json
x Test-Class-Moose-0.58/META.yml
x Test-Class-Moose-0.58/README
x Test-Class-Moose-0.58/t/
x Test-Class-Moose-0.58/t/author-pod-spell.t
x Test-Class-Moose-0.58/t/autouse.t
x Test-Class-Moose-0.58/t/basic.t
x Test-Class-Moose-0.58/t/environment.t
x Test-Class-Moose-0.58/t/include_classes.t
x Test-Class-Moose-0.58/t/include_exclude.t
x Test-Class-Moose-0.58/t/lib/
x Test-Class-Moose-0.58/t/parallel-role.t
x Test-Class-Moose-0.58/t/parallel.t
x Test-Class-Moose-0.58/t/parallellib/
x Test-Class-Moose-0.58/t/parameterized.t
x Test-Class-Moose-0.58/t/parameterizedlib/
x Test-Class-Moose-0.58/t/planlib/
x Test-Class-Moose-0.58/t/plans.t
x Test-Class-Moose-0.58/t/release-pod-syntax.t
x Test-Class-Moose-0.58/t/reporting.t
x Test-Class-Moose-0.58/t/reportpassed.t
x Test-Class-Moose-0.58/t/reportpassedlib/
x Test-Class-Moose-0.58/t/skip.t
x Test-Class-Moose-0.58/t/skip_all.t
x Test-Class-Moose-0.58/t/skiplib/
x Test-Class-Moose-0.58/t/taglib/
x Test-Class-Moose-0.58/t/tags.t
x Test-Class-Moose-0.58/t/test_control_methods.t
x Test-Class-Moose-0.58/t/taglib/PersonTest.pm
x Test-Class-Moose-0.58/t/taglib/TestsFor/
x Test-Class-Moose-0.58/t/taglib/TestsFor/Basic/
x Test-Class-Moose-0.58/t/taglib/TestsFor/Basic.pm
x Test-Class-Moose-0.58/t/taglib/TestsFor/MultipleExclude.pm
x Test-Class-Moose-0.58/t/taglib/TestsFor/Basic/Role.pm
x Test-Class-Moose-0.58/t/taglib/TestsFor/Basic/Subclass.pm
x Test-Class-Moose-0.58/t/taglib/TestsFor/Basic/WithRole.pm
x Test-Class-Moose-0.58/t/skiplib/TestsFor/
x Test-Class-Moose-0.58/t/skiplib/TestsFor/Basic.pm
x Test-Class-Moose-0.58/t/skiplib/TestsFor/SkipSomeMethods.pm
x Test-Class-Moose-0.58/t/reportpassedlib/TestsFor/
x Test-Class-Moose-0.58/t/reportpassedlib/TestsFor/Fail.pm
x Test-Class-Moose-0.58/t/reportpassedlib/TestsFor/FailChild.pm
x Test-Class-Moose-0.58/t/reportpassedlib/TestsFor/Pass.pm
x Test-Class-Moose-0.58/t/planlib/TestsFor/
x Test-Class-Moose-0.58/t/planlib/TestsFor/Attributes/
x Test-Class-Moose-0.58/t/planlib/TestsFor/Attributes.pm
x Test-Class-Moose-0.58/t/planlib/TestsFor/Person/
x Test-Class-Moose-0.58/t/planlib/TestsFor/Person.pm
x Test-Class-Moose-0.58/t/planlib/TestsFor/Person/Employee.pm
x Test-Class-Moose-0.58/t/planlib/TestsFor/Attributes/Subclass.pm
x Test-Class-Moose-0.58/t/parameterizedlib/TestsFor/
x Test-Class-Moose-0.58/t/parameterizedlib/TestsFor/Parameterized.pm
x Test-Class-Moose-0.58/t/parallellib/TestsFor/
x Test-Class-Moose-0.58/t/parallellib/TestsFor/Alpha/
x Test-Class-Moose-0.58/t/parallellib/TestsFor/Alpha.pm
x Test-Class-Moose-0.58/t/parallellib/TestsFor/Beta.pm
x Test-Class-Moose-0.58/t/parallellib/TestsFor/Sequential.pm
x Test-Class-Moose-0.58/t/parallellib/TestsFor/Alpha/Subclass.pm
x Test-Class-Moose-0.58/t/lib/PersonTest.pm
x Test-Class-Moose-0.58/t/lib/TestsFor/
x Test-Class-Moose-0.58/t/lib/TestsFor/Basic/
x Test-Class-Moose-0.58/t/lib/TestsFor/Basic.pm
x Test-Class-Moose-0.58/t/lib/TestsFor/Basic/Subclass.pm
x Test-Class-Moose-0.58/lib/Test/
x Test-Class-Moose-0.58/lib/Test/Class/
x Test-Class-Moose-0.58/lib/Test/Class/Moose/
x Test-Class-Moose-0.58/lib/Test/Class/Moose.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/AttributeRegistry.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Config.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Executor/
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Load.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Report/
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Report.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role/
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Runner.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Tutorial.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role/AutoUse.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role/Executor.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role/Parallel.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role/ParameterizedInstances.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role/Reporting.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Role/Timing.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Report/Instance.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Report/Method.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Report/Time.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Executor/Parallel.pm
x Test-Class-Moose-0.58/lib/Test/Class/Moose/Executor/Sequential.pm
Entering Test-Class-Moose-0.58
Checking configure dependencies from META.json
Checking if you have ExtUtils::MakeMaker 6.30 ... Yes (6.66)
Configuring Test-Class-Moose-0.58 ... Running Makefile.PL
Checking if your kit is complete...
Looks good
Writing Makefile for Test::Class::Moose
Writing MYMETA.yml and MYMETA.json
OK
Checking dependencies from MYMETA.json ...
Checking if you have Scalar::Util 0 ... Yes (1.41)
Checking if you have Test::Requires 0 ... Yes (0.06)
Checking if you have Carp::Always 0 ... Yes (0.13)
Checking if you have Parallel::ForkManager 0 ... Yes (1.03)
Checking if you have Benchmark 0 ... Yes (1.13)
Checking if you have Class::MOP 0 ... Yes (2.0802)
Checking if you have File::Spec 0 ... Yes (3.40)
Checking if you have Moose::Util::TypeConstraints 0 ... Yes (2.0802)
Checking if you have List::Util 0 ... Yes (1.41)
Checking if you have Test::Builder 0 ... Yes (1.001002)
Checking if you have File::Find 0 ... Yes (1.20)
Checking if you have Test::Most 0.32 ... Yes (0.34)
Checking if you have lib 0 ... Yes (0.63)
Checking if you have List::MoreUtils 0 ... Yes (0.33)
Checking if you have Moose 2.0000 ... Yes (2.0802)
Checking if you have warnings 0 ... Yes (1.13)
Checking if you have Test::Warnings 0 ... Yes (0.014)
Checking if you have Moose::Role 2.0000 ... Yes (2.0802)
Checking if you have TAP::Formatter::Color 0 ... Yes (3.30)
Checking if you have Try::Tiny 0 ... Yes (0.12)
Checking if you have namespace::autoclean 0 ... Yes (0.24)
Checking if you have Sub::Attribute 0 ... Yes (0.05)
Checking if you have Carp 0 ... Yes (1.26)
Checking if you have TAP::Stream 0.44 ... Yes (0.44)
Checking if you have strict 0 ... Yes (1.07)
Building and testing Test-Class-Moose-0.58 ... cp lib/Test/Class/Moose/Report/Time.pm blib/lib/Test/Class/Moose/Report/Time.pm
cp lib/Test/Class/Moose/Role/ParameterizedInstances.pm blib/lib/Test/Class/Moose/Role/ParameterizedInstances.pm
cp lib/Test/Class/Moose/Tutorial.pm blib/lib/Test/Class/Moose/Tutorial.pm
cp lib/Test/Class/Moose/Role/Reporting.pm blib/lib/Test/Class/Moose/Role/Reporting.pm
cp lib/Test/Class/Moose/Load.pm blib/lib/Test/Class/Moose/Load.pm
cp lib/Test/Class/Moose/Report/Instance.pm blib/lib/Test/Class/Moose/Report/Instance.pm
cp lib/Test/Class/Moose/Role/Parallel.pm blib/lib/Test/Class/Moose/Role/Parallel.pm
cp lib/Test/Class/Moose/Role/Timing.pm blib/lib/Test/Class/Moose/Role/Timing.pm
cp lib/Test/Class/Moose/Role/Executor.pm blib/lib/Test/Class/Moose/Role/Executor.pm
cp lib/Test/Class/Moose/Report/Method.pm blib/lib/Test/Class/Moose/Report/Method.pm
cp lib/Test/Class/Moose/Config.pm blib/lib/Test/Class/Moose/Config.pm
cp lib/Test/Class/Moose/Report.pm blib/lib/Test/Class/Moose/Report.pm
cp lib/Test/Class/Moose.pm blib/lib/Test/Class/Moose.pm
cp lib/Test/Class/Moose/Executor/Parallel.pm blib/lib/Test/Class/Moose/Executor/Parallel.pm
cp lib/Test/Class/Moose/Executor/Sequential.pm blib/lib/Test/Class/Moose/Executor/Sequential.pm
cp lib/Test/Class/Moose/Role/AutoUse.pm blib/lib/Test/Class/Moose/Role/AutoUse.pm
cp lib/Test/Class/Moose/AttributeRegistry.pm blib/lib/Test/Class/Moose/AttributeRegistry.pm
cp lib/Test/Class/Moose/Runner.pm blib/lib/Test/Class/Moose/Runner.pm
cp lib/Test/Class/Moose/Role.pm blib/lib/Test/Class/Moose/Role.pm
Manifying blib/man3/Test::Class::Moose::Report::Time.3
Manifying blib/man3/Test::Class::Moose::Role::ParameterizedInstances.3
Manifying blib/man3/Test::Class::Moose::Load.3
Manifying blib/man3/Test::Class::Moose::Role::Reporting.3
Manifying blib/man3/Test::Class::Moose::Tutorial.3
Manifying blib/man3/Test::Class::Moose::Report::Instance.3
Manifying blib/man3/Test::Class::Moose::Role::Executor.3
Manifying blib/man3/Test::Class::Moose::Role::Timing.3
Manifying blib/man3/Test::Class::Moose::Role::Parallel.3
Manifying blib/man3/Test::Class::Moose::Report.3
Manifying blib/man3/Test::Class::Moose::Config.3
Manifying blib/man3/Test::Class::Moose::Report::Method.3
Manifying blib/man3/Test::Class::Moose.3
Manifying blib/man3/Test::Class::Moose::Executor::Parallel.3
Manifying blib/man3/Test::Class::Moose::Executor::Sequential.3
Manifying blib/man3/Test::Class::Moose::Role::AutoUse.3
Manifying blib/man3/Test::Class::Moose::AttributeRegistry.3
Manifying blib/man3/Test::Class::Moose::Runner.3
Manifying blib/man3/Test::Class::Moose::Role.3
PERL_DL_NONLAZY=1 /data/apps/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
t/author-pod-spell.t ...... skipped: these tests are for testing by the author
t/autouse.t ............... ok
t/basic.t ................. ok
t/environment.t ........... ok
t/include_classes.t ....... ok
t/include_exclude.t ....... ok
t/parallel-role.t ......... ok
t/parallel.t .............. .........
t/parallel.t .............. ok
t/parameterized.t ......... ok
t/plans.t ................. ok
t/release-pod-syntax.t .... skipped: these tests are for release candidate testing
t/reporting.t ............. ok
t/reportpassed.t .......... Can't locate Fail.pm in @inc (@inc contains: t/reportpassedlib . /Users/jt/.cpanm/work/1435019167.26494/Test-Class-Moose-0.58/blib/lib /Users/jt/.cpanm/work/1435019167.26494/Test-Class-Moose-0.58/blib/arch /data/apps/lib/perl5/site_perl/5.16.2/darwin-2level /data/apps/lib/perl5/site_perl/5.16.2 /data/apps/lib/perl5/5.16.2/darwin-2level /data/apps/lib/perl5/5.16.2) at t/reportpassedlib/TestsFor/FailChild.pm line 2.
BEGIN failed--compilation aborted at t/reportpassedlib/TestsFor/FailChild.pm line 2.
Compilation failed in require at (eval 302) line 2.
BEGIN failed--compilation aborted at (eval 302) line 2.
BEGIN failed--compilation aborted at t/reportpassed.t line 5.
t/reportpassed.t .......... Dubious, test returned 2 (wstat 512, 0x200)
No subtests run
t/skip.t .................. ok
t/skip_all.t .............. skipped: This test must always skip_all and must never fail
t/tags.t .................. ok
t/test_control_methods.t .. ok

Test Summary Report

t/reportpassed.t (Wstat: 512 Tests: 0 Failed: 0)
Non-zero exit status: 2
Parse errors: No plan found in TAP output
Files=17, Tests=107, 13 wallclock secs ( 0.10 usr 0.03 sys + 5.38 cusr 0.35 csys = 5.86 CPU)
Result: FAIL
Failed 1/17 test programs. 0/107 subtests failed.
make: *** [test_dynamic] Error 255
FAIL
! Installing Test::Class::Moose failed. See /Users/jt/.cpanm/work/1435019167.26494/build.log for details. Retry with --force to force install it.

TCM Must always run control methods on skip

This is very fragile in part because there are fiddly bits that developers have to write together, but I have code that is conceptually like this:

package TestsFor::My::Client {
    use Test::Class::Moose extends => 'Test::Client::Base';

    sub test_startup {
        my $test = shift;
        $test->next::method;
        $test->test_skip("Get me outta here!");
    }

    sub test_shutdown {
        my $test = shift;
        say STDERR "We never see this output";
        $test->next::method;
    }

    # many test methods
}

If I run test_skip in test_startup, my test_shutdown is not run. We use our test_startup to start a transaction, our test_shutdown rolls back that transaction, but it doesn't. So the next test_startup tries to start another transaction and things go downhill from there.

After a bit of poking through TCM, I hit this:

$ git grep 'sub run_control_methods_on_skip'
lib/Test/Class/Moose.pm:sub run_control_methods_on_skip {0}
t/controllib/TestsFor/Control/SkipClass.pm:sub run_control_methods_on_skip {1}
t/controllib/TestsFor/Control/SkipMethod.pm:sub run_control_methods_on_skip {1}

So Test::Class::Moose says we should not run control methods on skip but two other classes say we should.

I don't know any reason why we shouldn't run the control methods. I recall our having discussed this, but I don't recall the details. The following makes our client test suite pass:

 $ git diff
diff --git a/lib/Test/Class/Moose.pm b/lib/Test/Class/Moose.pm
index 356a6f7..73ad796 100644
--- a/lib/Test/Class/Moose.pm
+++ b/lib/Test/Class/Moose.pm
@@ -237,7 +237,7 @@ sub test_setup    { }
 sub test_teardown { }
 sub test_shutdown { }

-sub run_control_methods_on_skip {0}
+sub run_control_methods_on_skip {1}

 __PACKAGE__->meta->make_immutable;

However, it makes the TCM test suite fail. Even after finding and reading your blog post about using Test2 with TCM, I find the test failures this generates to be rather impenetrable. I've tried reading the Test2 docs but the closest example I could find doesn't seem to match the sort of weird test failures I'm getting.

Thus, I think my change is correct, but I can't figure out the test suite to verify this!

In fact, I would think all references to run_control_methods_on_skip might need to be deleted since their values are hard-coded? (Otherwise, let people set this value if they have some weird need we haven't anticipated).

Here's an example of the errors:

# at /Users/ovid/Dropbox/Mine/projects/perl/test-class-moose/t/lib/Test/Events.pm line 17.
# +------------------+------------------+---------+------------------+-----+
# | PATH             | GOT              | OP      | CHECK            | LNs |
# +------------------+------------------+---------+------------------+-----+
# | [1]->pass()      | 0                | TRUE()  | TRUE             | 34  |
# |                  |                  |         |                  |     |
# | [1]->subevents() | Test2::Event::Ok | eq      | Test2::Event::Pl |     |
# | ->[0] <blessed>  |                  |         | an               |     |
# |                  |                  |         |                  |     |
# | [1]->subevents() | <DOES NOT EXIST> |         | SKIP             | 462 |
# | ->[0]->directive |                  |         |                  |     |
# | ()               |                  |         |                  |     |
# |                  |                  |         |                  |     |
# | [1]->subevents() | <DOES NOT EXIST> |         | all methods shou | 462 |
# | ->[0]->reason()  |                  |         | ld be skipped    |     |
# |                  |                  |         |                  |     |
# | [1]->subevents() | <DOES NOT EXIST> |         | 0                | 462 |
# | ->[0]->max()     |                  |         |                  |     |
# |                  |                  |         |                  |     |
# | [1]->subevents() | Test2::Event::Di | !exists | <DOES NOT EXIST> |     |
# | ->[1]            | ag=HASH(0x7fe93f |         |                  |     |
# |                  | df5db8)          |         |                  |     |
# |                  |                  |         |                  |     |
# | [1]->subevents() | Test2::Event::Di | !exists | <DOES NOT EXIST> |     |
# | ->[2]            | ag=HASH(0x7fe93f |         |                  |     |
# |                  | df6190)          |         |                  |     |
# |                  |                  |         |                  |     |
# | [1]->subevents() | Test2::Event::Pl | !exists | <DOES NOT EXIST> |     |
# | ->[3]            | an=HASH(0x7fe93f |         |                  |     |
# |                  | 319ec0)          |         |                  |     |
# |                  |                  |         |                  |     |
# | [2] <blessed>    | Test2::Event::Di | eq      | Test2::Event::Su |     |
# |                  | ag               |         | btest            |     |
# |                  |                  |         |                  |     |
# | [2]->name()      | <DOES NOT EXIST> |         | TestsFor::SkipSo | 462 |
# |                  |                  |         | meMethods        |     |
# |                  |                  |         |                  |     |
# | [2]->pass()      | <DOES NOT EXIST> | TRUE()  | TRUE             | 38  |
# | [2]->subevents() | <DOES NOT EXIST> |         | <ARRAY>          | 462 |
# |                  |                  |         |                  |     |
# | [3]              | Test2::Event::Su | !exists | <DOES NOT EXIST> |     |
# |                  | btest=HASH(0x7fe |         |                  |     |
# |                  | 93fdf66d0)       |         |                  |     |
# +------------------+------------------+---------+------------------+-----+
ok 2 - timing data for entire report

Please make _run_test_class and _run_test_method public

It's trivial to override the executor in Test::Class::Moose::Runner to make a custom subclass, but when subclassing Test::Class::Moose::Executor::Sequential, I have to use the private methods _run_test_class and _run_test_method with my before modifiers.

It would be lovely if those were made public so I didn't feel too guilty about those. If those were public, I could easily publish modules which allow verbose output like the following (without needing to extend functionality with PRs such as #76):

screen shot 2017-12-16 at 11 15 43 am

Show class/method names in non-verbose mode.

This is not a pull request because it's a proof of concept. This branch allows you to pass a verbose switch to the constructor to make it easier to see class and method names while running in non-verbose mode. I've often wanted that and in this case, it's because of this:

$ prove t/tcm.t
t/tcm.t .. 283/303

That was my tests hanging on test 283, but having no real way of knowing which test it was. Running the full test suite in verbose mode solved that, but it would be nice to see test progress without full verbose mode.

Thus, the branch I pushed allows that, but the output is very ugly. Further, I'm not familiar with the new Test::Builder, so the tests were mystifying to me. Thus, there's code and docs, but no tests. However, it runs just fine on my test suite.

This ticket is more for discussion than for merging the code (unless you think it's useful enough for that).

Throwing an exception object in a test control method results in the object being dumped to the screen

When an exception object is thrown from a test control method while using prove, the contents of the object are dumped to the screen rather than the stringified object.

For instance, with:

package TestsFor::Exception;

use Test::Class::Moose;
use Throwable::Error;

sub test_setup {
    Throwable::Error->throw('goodbye');
}

sub test_ok {
    ok(1);
}

package main;

use Test::Class::Moose::CLI;
Test::Class::Moose::CLI->new_with_options->run;

You get these 614 lines of output.

Note that this does not happen with yath. It could arguably be a bug in the Test2 TAP formatter. However, it is limited to exceptions in TCM test control methods.

parallel.t hangs on Windows

Test-Class-Moose-0.55
tested on 5.20.0, 5.16.0, 5.10.1

Can't dup STDOUT:  Bad file descriptor at C:/Strawberry200rc1/perl/lib/Test/Builder.pm line 1948.
    Test::Builder::_open_testhandles(Test::Builder=HASH(0x34ecbdc)) called at C:/Strawberry200rc1/perl/lib/Test/Builder.pm line 1927
    Test::Builder::_dup_stdhandles(Test::Builder=HASH(0x34ecbdc)) called at C:/Strawberry200rc1/perl/lib/Test/Builder.pm line 467
    Test::Builder::reset(Test::Builder=HASH(0x34ecbdc)) called at C:/Strawberry200rc1/perl/lib/Test/Builder.pm line 145
    Test::Builder::create("Test::Builder") called at C:/Strawberry200rc1/perl/lib/Test/Builder.pm line 197
    Test::Builder::child(Test::Builder=HASH(0x2fd816c), "test_second") called at C:/Strawberry200rc1/perl/lib/Test/Builder.pm line 251
    Test::Builder::subtest(Test::Builder=HASH(0x2fd816c), "test_second", CODE(0x1d9b3e4)) called at lib/Test/Class/Moose/Role/Executor.pm line 304
    Test::Class::Moose::Role::Executor::_tcm_run_test_method(Test::Class::Moose::Executor::Parallel=HASH(0x31658c4), TestsFor::Alpha::Subclass=HASH(0x3306aa4), "test_second", Test::Class::Moose::Report::Instance=HASH(0x34ec144)) called at C:/Strawberry200rc1/perl/vendor/lib/Class/MOP/Method/Wrapped.pm line 54
    Class::MOP::Method::Wrapped::__ANON__(Test::Class::Moose::Executor::Parallel=HASH(0x31658c4), TestsFor::Alpha::Subclass=HASH(0x3306aa4), "test_second", Test::Class::Moose::Report::Instance=HASH(0x34ec144)) called at C:/Strawberry200rc1/perl/vendor/lib/Class/MOP/Method/Wrapped.pm line 92
    Test::Class::Moose::Executor::Parallel::_tcm_run_test_method(Test::Class::Moose::Executor::Parallel=HASH(0x31658c4), TestsFor::Alpha::Subclass=HASH(0x3306aa4), "test_second", Test::Class::Moose::Report::Instance=HASH(0x34ec144)) called at lib/Test/Class/Moose/Role/Executor.pm line 130
    Test::Class::Moose::Role::Executor::_tcm_run_test_instance(Test::Class::Moose::Executor::Parallel=HASH(0x31658c4), "TestsFor::Alpha::Subclass", TestsFor::Alpha::Subclass=HASH(0x3306aa4)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 47
    Test::Class::Moose::Executor::Parallel::__ANON__(Test::Class::Moose::Executor::Parallel=HASH(0x31658c4), "TestsFor::Alpha::Subclass", TestsFor::Alpha::Subclass=HASH(0x3306aa4)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 129
    Test::Class::Moose::Executor::Parallel::_run_parallel_jobs(Test::Class::Moose::Executor::Parallel=HASH(0x31658c4), Parallel::ForkManager=HASH(0x2271134), ARRAY(0x330690c)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 68
    Test::Class::Moose::Executor::Parallel::runtests() called at C:/Strawberry200rc1/perl/vendor/lib/Moose/Meta/Method/Delegation.pm line 113
    Test::Class::Moose::Runner::runtests() called at t/parallel.t line 18
No TAP received from child process -1304! at lib/Test/Class/Moose/Executor/Parallel.pm line 105.
    Test::Class::Moose::Executor::Parallel::__ANON__(-1304, 9, undef, 0, 0, undef) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 586
    Parallel::ForkManager::on_finish(Parallel::ForkManager=HASH(0x99f054), -1304, 9, undef, 0, 0, undef) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 559
    Parallel::ForkManager::wait_one_child(Parallel::ForkManager=HASH(0x99f054), undef) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 570
    Parallel::ForkManager::wait_all_children(Parallel::ForkManager=HASH(0x99f054)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 140
    Test::Class::Moose::Executor::Parallel::_run_parallel_jobs(Test::Class::Moose::Executor::Parallel=HASH(0x1a51cf4), Parallel::ForkManager=HASH(0x99f054), ARRAY(0x1a9d6a4)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 68
    Test::Class::Moose::Executor::Parallel::runtests(Test::Class::Moose::Executor::Parallel=HASH(0x1a51cf4)) called at C:/Strawberry200rc1/perl/vendor/lib/Moose/Meta/Method/Delegation.pm line 113
    Test::Class::Moose::Runner::runtests(Test::Class::Moose::Runner=HASH(0x3f83ac)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 105.
    Test::Class::Moose::Executor::Parallel::__ANON__(-1304, 9, undef, 0, 0, undef) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 586
    Parallel::ForkManager::on_finish(Parallel::ForkManager=HASH(0x99f054), -1304, 9, undef, 0, 0, undef) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 559
    Parallel::ForkManager::wait_one_child(Parallel::ForkManager=HASH(0x99f054), undef) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 570
    Parallel::ForkManager::wait_all_children(Parallel::ForkManager=HASH(0x99f054)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 140
    Test::Class::Moose::Executor::Parallel::_run_parallel_jobs(Test::Class::Moose::Executor::Parallel=HASH(0x1a51cf4), Parallel::ForkManager=HASH(0x99f054), ARRAY(0x1a9d6a4)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 68
    Test::Class::Moose::Executor::Parallel::runtests(Test::Class::Moose::Executor::Parallel=HASH(0x1a51cf4)) called at C:/Strawberry200rc1/perl/vendor/lib/Moose/Meta/Method/Delegation.pm line 113
    Test::Class::Moose::Runner::runtests(Test::Class::Moose::Runner=HASH(0x3f83ac)) called at t/parallel.t line 18
Terminating on signal SIGINT(2)
 at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 649.
    Parallel::ForkManager::_NT_waitpid(Parallel::ForkManager=HASH(0x99f054), -1, 0) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 539
    Parallel::ForkManager::wait_one_child(Parallel::ForkManager=HASH(0x99f054), undef) called at C:/Strawberry200rc1/perl/site/lib/Parallel/ForkManager.pm line 570
    Parallel::ForkManager::wait_all_children(Parallel::ForkManager=HASH(0x99f054)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 140
    Test::Class::Moose::Executor::Parallel::_run_parallel_jobs(Test::Class::Moose::Executor::Parallel=HASH(0x1a51cf4), Parallel::ForkManager=HASH(0x99f054), ARRAY(0x1a9d6a4)) called at lib/Test/Class/Moose/Executor/Parallel.pm line 68
    Test::Class::Moose::Executor::Parallel::runtests(Test::Class::Moose::Executor::Parallel=HASH(0x1a51cf4)) called at C:/Strawberry200rc1/perl/vendor/lib/Moose/Meta/Method/Delegation.pm line 113
    Test::Class::Moose::Runner::runtests(Test::Class::Moose::Runner=HASH(0x3f83ac)) called at t/parallel.t line 18

Passing report to test methods should be deprecated

I really want to use sub signatures with tcm, but it's ugly having to account for the little-used $report variable passed to method (especially since that's available via $test->report. It would be nice if we deprecated passing that (if we haven't already) and schedule it for removal.

Test::Class::Moose::Role::AutoUse and no corresponding base class

When I write a base class, it's often something like:

package TestsFor::SomeCompany;

use Test::Class::Moose;
with qw(Test::Class::Moose::Role::Autouse);

1;

That's always worked (so far) because there's almost always a corresponding SomeCompany.pm file. Today that turned out to not be the case. However, we should try to decouple that and have the autouse role recognize when we don't need a corresponding class. This was a coupling mistake I made and am thinking about a clean solution for the fix. Until then, the following workaround in your TCM base class should suffice:

around 'get_class_name_to_use' => sub {
    my $orig = shift;
    my $self = shift;

    if ( __PACKAGE__ eq ref $self ) {
        return '';
    }
    return $self->$orig(@_);
};

Missing Sub::Attribute dependency in Test-Class-Moose-0.50

Hello,

I just tried to install Test::Class::Moose v0.50 (using cpanm) and the test t/plans.t was dying with:

Invalid CODE attribute: Test at $PERLBREW/perls/perl-5.18.2/lib/5.18.2/x86_64-linux-thread-multi/attributes.pm line 83.

I installed Sub::Attribute and then was able to install (and enjoy!) Test::Class::Moose.

I thought a module dependency was missing from the META.json, but it seems "Sub::Attribute" is actually just recommended there.

Thank you for this great module,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.