NAME
Test::YAFT - Yet another testing framework
SYNOPSIS
use Test::YAFT;
it q (should pass this test)
=> got => scalar do { ... }
=> expect => $expected_value
;
DISCLAIMER
Please accept the fact that I'm not English native speaker so this documentation may contain improper grammar or wording making it harder to understand.
If you encounter such place, please visit project's issue tracking.
DESCRIPTION
Test::YAFT combines features of multiple test libraries, providing a BDD-inspired, AAA-based, Context oriented testing approach.
Test Message First
The test message is always the first argument to every assumption function. This is a core design principle that ensures tests are self-documenting and readable.
it q (should increment counter)
=> got => $counter
=> expect => 42
;
All other arguments use a named parameter approach, making tests explicit and easy to understand.
AAA Pattern
Test::YAFT provides the Arrange-Act-Assert pattern:
- Arrange - Set up test context using
arrange { } - Act - Execute code under test using
got { }oract { } - Assert - Verify results using
expectorthrows
BDD Inspired
The naming conventions (it, assume, there) are inspired by Behaviour-Driven Development, allowing tests to read as specifications:
it q (should return user's full name)
=> got => $user->full_name
=> expect => q (John Doe)
;
assume q (the user's full name is correctly constructed)
=> got => $user->full_name
=> expect => q (John Doe)
;
Test::Deep Integration
Test::YAFT uses Test::Deep under the hood, enabling powerful nested structure matching and custom comparators.
Additionally, Test::Differences is used to report differences when tests fail.
Common Assumption Arguments
got- The value under test-
=> got => $value_under_test => got { return $value_under_test } expect- The expected value (Test::Deep::Cmp or plain value)-
=> expect => expect_foo (...) throws- Expected exception (when testing for errors)-
=> throws => expect_foo (...) with_*- Context setup-
=> with_name => $name => arrange { name => $name } diag- Custom diagnostic message-
=> diag => q (Custom diagnostic message) => diag => sub { q (Computed custom diagnostic message) }
Computed got Value
The got { } block computes the value under test within an eval, automatically checking for unexpected exceptions:
it q (should calculate total)
=> got { $cart->calculate_total }
=> expect => 99.99
;
When throws is specified, the test expects the code to die:
it q (should reject negative quantity)
=> got { $cart->add_item (quantity => -1) }
=> throws => expect_obj_isa (My::X::Positive_Quantity::)
;
To specify such block across multiple assumptions, use the act { } block.
Context
Test::YAFT uses a hierarchical context system to manage test state.
Each context enforces the following constraints:
- Only one act {} block can be defined
- Each property name can only be arranged once
There is one root context shared by all test files within the same process. Each subtest and each assumption creates a new sub-context.
Sub-contexts inherit values from their parent context and allow you to override them (once). Changes in a sub-context do not affect the parent or sibling contexts. Once a value has been read from a parent, it becomes immutable and can no longer be overridden.
See also: test_frame
GETTING STARTED
For a tutorial-like introduction, see Test::YAFT::Introduction.
If you are migrating from another testing library, these guides may help:
- Test::YAFT for Test::Deep users
- Test::YAFT for Test::Exceptions users
- Test::YAFT for Test::More users
- Test::YAFT for Test::Spec users
- Test::YAFT for Test::Warnings users
EXPORTING
Test::YAFT exports symbols using Exporter::Tiny.
Export Tags
:all-
All exported functions.
:assumptions-
Assumption functions (exported by default).
:default-
All functions exported by default.
:expectations-
Expectation functions (exported by default).
:foundations-
Foundation functions (not exported by default).
:utils-
Utility functions (exported by default).
Selective Import
# Import specific functions
use Test::YAFT qw (it expect_true);
# Import only foundation functions
use Test::YAFT qw (:foundations);
# Exclude specific functions
use Test::YAFT qw (!fail);
See Exporter::Tiny for more import options.
OVERLOADED OPERATORS
Test::YAFT overloads operators for Test::Deep expectations, enabling tabular-style expectation definitions for improved readability.
!,~, Unary--
assume q (...) => expect => ! expectation ; assume q (...) => expect => ~ expectation ; assume q (...) => expect => - expectation ;Creates a complementary expectation (negation).
- Binary
+ -
assume q (user should have valid properties) => expect => + expectation # must pass + expectation # must pass as well + expectation # must pass as well ;Combines multiple expectations where all must pass. Same behaviour as Test::Deep's
&operator, but enables better vertical alignment for improved readability. - Binary
- -
assume q (...) => expect => + expectation # must pass + expectation # must pass as well - expectation # must not pass ;Combines expectations where
-negates the expectation. Equivalent to+ !.
ASSUMPTIONS
use Test::YAFT qw (:assumptions);
Assumption functions perform actual value comparison and report test results. They are exported by default.
Every assumption accepts the test message as the first positional parameter, with remaining parameters using the named approach.
When an assumption performs multiple internal expectations, it reports as a single test using the provided message, failing early.
assume
assume q (meaningful sentence)
=> got => ...
=> expect => ...
;
The primary test primitive. It creates its own sub-context so already arranged values can be redefined per assumption when needed.
Accepted parameters:
- arrange
-
assume q (...) => arrange { foo => q (bar) } => arrange { bar => q (baz) } ... ;<
arrange { }> blocks are evaluated in the context of the assumption's sub-context before resolving the value under test.Multiple <
arrange { }> blocks are evaluated in order. - diag
-
Custom diagnostic message, printed on failure. When specified, no other diagnostic message is printed.
Can be a string, arrayref of strings, or coderef. Coderef receives the Test::Deep stack and value under test as parameters.
- expect
-
Expected value. When specified along with computed
gotvalue, an additional check verifies the code did not die before comparison. - got
-
Value under test. When <
got { }> is used, the block is evaluated and its error status is checked before comparison. - throws
-
Expected exception. When specified along with computed
gotvalue, an additional check verifies the code did die before comparison.When both
expectandthrowsare specified,throwstakes precedence.See also Test::YAFT::Test::Exception.
fail
return fail q (what failed);
return fail q (what failed)
=> diag => q (diagnostic message)
;
return fail q (what failed)
=> diag => sub { q (diagnostic message) }
;
Always fails the test. Accepts an optional diag parameter for diagnostic messages.
When diag is a coderef, it is executed and its result is passed to diag.
had_no_warnings
had_no_warnings;
had_no_warnings q (title);
Verifies that no warnings were emitted.
See also Test::Warnings::had_no_warnings.
it
it q (should be ...)
=> got => ...
=> expect => ...
;
Alias for "assume". Use when forming sentences that read naturally with "it".
nok
nok q (shouldn't be ...)
=> got => ...
;
Shortcut expecting a boolean false value.
ok
ok q (should be ...)
=> got => ...
;
Shortcut expecting a boolean true value.
pass
pass q (what passed);
Always passes the test.
there
there q (should be ...)
=> got => ...
=> expect => ...
;
Alias for it. Provides a convenient word for forming meaningful English sentences.
EXPECTATIONS
use Test::YAFT qw (:expectations);
Expectation functions return Test::Deep::Cmp objects describing expected values. They are exported by default.
expect_all
Re-exported from "all" in Test::Deep.
expect_any
Re-exported from "any" in Test::Deep.
expect_array
Re-exported from "array" in Test::Deep.
expect_array_each
Re-exported from "array_each" in Test::Deep.
expect_array_elements_only
Re-exported from "arrayelementsonly" in Test::Deep.
expect_array_length
Re-exported from "arraylength" in Test::Deep.
expect_array_length_only
Re-exported from "arraylengthonly" in Test::Deep.
expect_bag
Re-exported from "bag" in Test::Deep.
expect_blessed
Re-exported from "blessed" in Test::Deep.
expect_bool
Re-exported from "bool" in Test::Deep.
expect_code
Re-exported from "code" in Test::Deep.
expect_compare
expect_compare (q (<=), $max)
Similar to "cmp_ok" in Test::More but provided as an expectation, allowing combination with other Test::YAFT expectations.
expect_complement_to
expect_complement_to (42)
Negative expectation. Usually it is easier to use the overloaded complement operators ! or ~.
expect_false
Boolean expectation for false values.
expect_hash
Re-exported from "hash" in Test::Deep.
expect_hash_each
Re-exported from "hash_each" in Test::Deep.
expect_hash_keys
Re-exported from "hashkeys" in Test::Deep.
expect_hash_keys_only
Re-exported from "hashkeysonly" in Test::Deep.
expect_isa
Re-exported from "Isa" in Test::Deep. Instance or inheritance expectation.
expect_listmethods
Re-exported from "listmethods" in Test::Deep.
expect_methods
Re-exported from "methods" in Test::Deep.
expect_no_class
Re-exported from "noclass" in Test::Deep.
expect_none
Re-exported from "none" in Test::Deep.
expect_none_of
Re-exported from "noneof" in Test::Deep.
expect_num
Re-exported from "num" in Test::Deep.
expect_obj_isa
Re-exported from "obj_isa" in Test::Deep.
expect_re
Re-exported from "re" in Test::Deep.
expect_ref_type
Re-exported from "reftype" in Test::Deep.
expect_regexp_matches
Re-exported from "regexpmatches" in Test::Deep.
expect_regexp_only
Re-exported from "regexponly" in Test::Deep.
expect_regexpref
Re-exported from "regexpref" in Test::Deep.
expect_regexpref_only
Re-exported from "regexprefonly" in Test::Deep.
expect_scalarref
Re-exported from "scalarref" in Test::Deep.
expect_scalarref_only
Re-exported from "scalarrefonly" in Test::Deep.
expect_set
Re-exported from "set" in Test::Deep.
expect_shallow
Re-exported from "shallow" in Test::Deep.
expect_str
Re-exported from "str" in Test::Deep.
expect_subbag
Re-exported from "subbagof" in Test::Deep.
expect_subbag_of
Re-exported from "subbagof" in Test::Deep.
expect_subhash
Re-exported from "subhashof" in Test::Deep.
expect_subhash_of
Re-exported from "subhashof" in Test::Deep.
expect_subset
Re-exported from "subsetof" in Test::Deep.
expect_subset_of
Re-exported from "subsetof" in Test::Deep.
expect_superbag
Re-exported from "superbagof" in Test::Deep.
expect_superbag_of
Re-exported from "superbagof" in Test::Deep.
expect_superhash
Re-exported from "superhashof" in Test::Deep.
expect_superhash_of
Re-exported from "superhashof" in Test::Deep.
expect_superset
Re-exported from "supersetof" in Test::Deep.
expect_superset_of
Re-exported from "supersetof" in Test::Deep.
expect_true
Boolean expectation for true values.
expect_use_class
Re-exported from "useclass" in Test::Deep.
expect_value
=> expect => expect_value (42)
Wraps any value as an expectation.
ignore
Re-exported from "ignore" in Test::Deep.
UTILITIES
use Test::YAFT qw (:utils);
Utility functions help organise tests. They are exported by default.
act { }
act { GET qq (/countries/$_[0]) }
q (continent)
;
it q (should list countries)
=> with_continent => q (europe)
=> expect => ...
;
Defines a shared computation for got across multiple assumptions. The block receives dependency values as arguments.
Dependencies are specified after the block and are provided via arrange { } block or via with_NAME parameters in assumptions.
arrange { }
arrange { foo => q (bar) };
it q (should ...)
=> arrange { foo => q (bar2) }
=> got { $foo->method (deduce q (foo)) }
=> expect => ...
;
Sets up test context by providing values to Context::Singleton.
When called in void context, values are proclaimed immediately. When used as a parameter, values are proclaimed in the test-local frame.
Returns a guard object evaluated in the frame valid at the time of evaluation.
BAIL_OUT
Reexported "BAIL_OUT" in Test::More
diag
Re-exported from "diag" in Test::More.
done_testing
Re-exported from "done_testing" in Test::More.
explain
Re-exported from "explain" in Test::More.
got { }
it q (should die)
=> got { $foo->do_something }
=> throws => expect_obj_isa (...)
;
Specifies code to compute the test value. The block is evaluated in an eval, and it checks the error status before comparison.
Use with throws to test that code should die.
note
Re-exported from "note" in Test::More.
plan
Re-exported from "plan" in Test::More.
skip
Re-exported from "skip" in Test::More.
subtest
subtest q (title) => sub {
...;
};
Similar to "subtest" in Test::More but also creates a new Context::Singleton frame for each subtest.
todo_skip
Re-exported from "todo_skip" in Test::More.
FOUNDATIONS
use Test::YAFT qw (:foundations);
Foundation functions help build custom assumptions, expectations, and tools. They are not exported by default.
cmp_details
use Test::YAFT qw (cmp_details);
my ($ok, $stack) = cmp_details ($got, $expected);
Re-exported from "cmp_details" in Test::Deep.
deep_diag
use Test::YAFT qw (deep_diag);
deep_diag ($stack);
Re-exported from "deep_diag" in Test::Deep.
eq_deeply
use Test::YAFT qw (eq_deeply);
if (eq_deeply ($got, $expected)) {
...
}
Re-exported from "eq_deeply" in Test::Deep.
test_deep_cmp
Creates an anonymous Test::YAFT comparator class. Returns the created class name.
sub expect_foo {
state $class = test_deep_cmp (
isa => ...,
descend => ...,
renderGot => ...,
);
$class->new (@_);
}
Accepted parameters:
- isa => <PACKAGE>
-
Parent class, default: Test::YAFT::Cmp.
- <METHOD> => <CODEREgt
-
Every other parameter is treated as a method to install.
test_frame (&)
use Test::YAFT qw (test_frame);
sub my_assumption {
test_frame {
...
};
}
Utility for building custom assumptions. Handles:
- Adjusting "level" in Test::Builder
- Creating "frame" in Context::Singleton
CONTRIBUTING
Contributions are welcome!
- Repository: https://github.com/happy-barney/perl-Test-YAFT
- Report issues: https://github.com/happy-barney/perl-Test-YAFT/issues
- Questions and ideas: https://github.com/happy-barney/perl-Test-YAFT/discussions
AUTHOR
Branislav Zahradník <barney@cpan.org>
COPYRIGHT AND LICENSE
Test::YAFT distribution is distributed under the Artistic License 2.0.