{"id":15557714,"url":"https://github.com/fgasper/p5-test-class-tiny","last_synced_at":"2025-08-23T00:18:15.280Z","repository":{"id":56839011,"uuid":"230098744","full_name":"FGasper/p5-Test-Class-Tiny","owner":"FGasper","description":"CPAN’s Test::Class::Tiny","archived":false,"fork":false,"pushed_at":"2022-08-02T12:42:45.000Z","size":48,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-03T13:45:13.077Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FGasper.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-25T12:17:22.000Z","updated_at":"2022-08-02T12:42:48.000Z","dependencies_parsed_at":"2022-08-29T02:52:09.340Z","dependency_job_id":null,"html_url":"https://github.com/FGasper/p5-Test-Class-Tiny","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Test-Class-Tiny","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Test-Class-Tiny/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Test-Class-Tiny/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FGasper%2Fp5-Test-Class-Tiny/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FGasper","download_url":"https://codeload.github.com/FGasper/p5-Test-Class-Tiny/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246135739,"owners_count":20729056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T15:20:26.897Z","updated_at":"2025-03-29T03:46:31.682Z","avatar_url":"https://github.com/FGasper.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NAME\n\nTest::Class::Tiny - xUnit in Perl, simplified\n\n# SYNOPSIS\n\n    package t::mytest;\n\n    use parent qw( Test::Class::Tiny );\n\n    __PACKAGE__-\u003eruntests() if !caller;\n\n    sub T_startup_something {\n        # Runs at the start of the test run.\n    }\n\n    sub something_T_setup {\n        # Runs before each normal test function\n    }\n\n    # Expects 2 assertions:\n    sub T2_normal {\n        ok(1, 'yes');\n        ok( !0, 'no');\n    }\n\n    # Ignores assertion count:\n    sub T0_whatever {\n        ok(1, 'yes');\n    }\n\n    sub T_teardown_something {\n        # Runs after each normal test function\n    }\n\n    sub T_shutdown_something {\n        # Runs at the end of the test run.\n    }\n\n# STATUS\n\nThis module is **EXPERIMENTAL**. If you use it, you MUST check the changelog\nbefore upgrading to a new version. Any CPAN distributions that use this module\ncould break whenever this module is updated.\n\n# DESCRIPTION\n\n[Test::Class](https://metacpan.org/pod/Test%3A%3AClass) is the de facto standard xUnit implementation in Perl.\nIt’s got quite a long dependency chain, though, so it’s awkward to use in\nCPAN projects.\n\nThis module offers a lighter alternative with a similar syntax.\n\n# HOW (AND WHY) TO USE THIS MODULE\n\nxUnit encourages you to organize test logic into independent chunks\nrather than a single, monolithic script. This benefits your tests in the\nsame way it helps your production code: reusability, modularity, etc.\n\nxUnit provides standard hooks for:\n\n- startup: The start of all tests\n- setup: The start of an individual test group (i.e., Perl function)\n- teardown: The end of an individual test group\n- shutdown: The end of all tests\n\nTo write functions that execute at these points in the workflow,\nname those functions with the prefixes `T_startup_`, `T_setup_`,\n`T_teardown_`, or `T_shutdown_`. **Alternatively**, name such functions\nwith the _suffixes_ `_T_startup`, `_T_setup`, `_T_teardown`, or\n`_T_shutdown`.\n\nTo write a test function—i.e., a function that actually runs some\nassertions—prefix the function name with `T`, the number of test assertions\nin the function, then an underscore. For example, a function that contains\n9 assertions might be named `T9_check_validation()`. If that function\ndoesn’t run exactly 9 assertions, a test failure is produced.\n\nTo forgo counting test assertions, use 0 as the test count, e.g.,\n`T0_check_validation()`.\n\nYou may alternatively use suffix-style naming for test functions well,\ne.g., `check_validation_T9()`, `check_validation_T0()`.\n\nThe above convention is a significant departure from [Test::Class](https://metacpan.org/pod/Test%3A%3AClass),\nwhich uses Perl subroutine attributes to indicate this information.\nUsing method names is dramatically simpler to implement and also easier\nto type.\n\nIn most other respects this module attempts to imitate [Test::Class](https://metacpan.org/pod/Test%3A%3AClass).\n\n## PLANS\n\nThe concept of a global “plan” (i.e., an expected number of assertions)\nisn’t all that sensible with xUnit because each test function has its\nown plan. So, ideally the total number of expected assertions for a given\ntest module is just the sum of all test functions’ expected assertions.\n\nThus, currently, `runtests()` sets the [Test2::Hub](https://metacpan.org/pod/Test2%3A%3AHub) object’s plan to\n`no_plan` if the plan is undefined.\n\n# TEST INHERITANCE\n\nLike [Test::Class](https://metacpan.org/pod/Test%3A%3AClass), this module seamlessly integrates inherited methods.\nTo have one test module inherit another module’s tests, just make that\nfirst module a subclass of the latter.\n\n**CAVEAT EMPTOR:** Inheritance in tests, while occasionally useful, can also\ncomplicate maintenance over time if overused.\n\n# RUNNING YOUR TEST\n\nTo use this module to write normal Perl test scripts, just define\nthe script’s package (ideally not `main`, but it’ll work) as a subclass of\nthis module. Then put the following somewhere in the script:\n\n    __PACKAGE__-\u003eruntests() if !caller;\n\nYour test will thus execute as a “modulino”.\n\n# SPECIAL FEATURES\n\n- As in [Test::Class](https://metacpan.org/pod/Test%3A%3AClass), a `SKIP_CLASS()` method may be defined. If this\nmethod returns truthy, then the class’s tests are skipped, and that truthy\nreturn is given as the reason for the skip.\n- The `TEST_METHOD` environment variable is honored as in [Test::Class](https://metacpan.org/pod/Test%3A%3AClass).\n- [Test::Class](https://metacpan.org/pod/Test%3A%3AClass)’s `fail_if_returned_early()` method is NOT recognized\nhere because an early return will already trigger a failure.\n- Within a test method, `num_tests()` may be called to retrieve the\nnumber of expected test assertions.\n- To define a test function whose test count isn’t known until runtime,\nname it **without** the usual `T$num` prefix, then at runtime do:\n\n        $test_obj-\u003enum_method_tests( $name, $count )\n\n    See `t/` in the distribution for an example of this.\n\n# COMMON PITFALLS\n\nAvoid the following:\n\n- Writing startup logic outside of the module class, e.g.:\n\n        if (!caller) {\n            my $mock = Test::MockModule-\u003enew('Some::Module');\n            $mock-\u003eredefine('somefunc', sub { .. } );\n\n            __PACKAGE__-\u003eruntests();\n        }\n\n    The above works _only_ if the test module runs in its own process; if you try\n    to run this module with anything else it’ll fail because `caller()` will be\n    truthy, which will prevent the mocking from being set up, which your test\n    probably depends on.\n\n    Instead of the above, write a wrapper around `runtests()`, thus:\n\n        sub runtests {\n            my $self = shift;\n\n            my $mock = Test::MockModule-\u003enew('Some::Module');\n            $mock-\u003eredefine('somefunc', sub { .. } );\n\n            $self-\u003eSUPER::runtests();\n        }\n\n    This ensures your test module will always run with the intended mocking.\n\n- REDUX: Writing startup logic outside of the module class, e.g.:\n\n        my $mock = Test::MockModule-\u003enew('Some::Module');\n        $mock-\u003eredefine('somefunc', sub { .. } );\n\n        __PACKAGE__-\u003eruntests() if !caller;\n\n    This is even worse than before because the mock will be global, which\n    will quietly apply it where we don’t intend. This produces\n    action-at-a-distance bugs, which can be notoriously hard to find.\n\n# SEE ALSO\n\nBesides [Test::Class](https://metacpan.org/pod/Test%3A%3AClass), you might also look at the following:\n\n- [Test2::Tools::xUnit](https://metacpan.org/pod/Test2%3A%3ATools%3A%3AxUnit) also implements xUnit for [Test2](https://metacpan.org/pod/Test2) but doesn’t\nallow inheritance.\n- [Test::Class::Moose](https://metacpan.org/pod/Test%3A%3AClass%3A%3AMoose) works with [Test2](https://metacpan.org/pod/Test2), but the [Moose](https://metacpan.org/pod/Moose) requirement\nmakes use in CPAN modules problematic.\n\n# AUTHOR\n\nCopyright 2019 [Gasper Software Consulting](http://gaspersoftware.com) (FELIPE)\n\n# LICENSE\n\nThis code is licensed under the same license as Perl itself.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgasper%2Fp5-test-class-tiny","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffgasper%2Fp5-test-class-tiny","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffgasper%2Fp5-test-class-tiny/lists"}