Asserto is a clean, fluent and powerful assertion library for python. We recommend using pytest
as a test
runner but asserto will work well with any test runner.
Asserto was developed using pytest as it's test runner and has a
pytest-asserto
plugin that exposes asserto through a fixture. Asserto will work on any runner or even without one. Note: It is common practice for a test runner to apply assertion rewriting to change the behaviour of theassert
keyword under the hood.
The main features of asserto are (and will be):
- Chainable and Fluent API.
- Ability for both
Hard
andSoft
assertions. - Rich diffs to highlight problems, reduce churn and improve efficiency and debug-ability.
- Dynamic assertions; check any obj attribute or invoke any of its function types.
- Robust set of methods out of the box for common types.
- Extensibility. Bolt on your own assertions at runtime.
- Human error detection, elaborate warnings when something is amiss.
- Much more to come.
Asserto
exposes a fully fluent API for chaining assertions against a value.
from asserto import asserto
def test_multiple_assert_fluency() -> None:
asserto("Hello").has_length(5).match(r"\w{5}$").ends_with("lo").starts_with("Hel")
Asserto
Has soft
capabilities; allowing multiple assertions to be performed before failing with a
summary of the failures.
from asserto import asserto
def test_baz() -> None:
with asserto("Baz") as context:
# asserto when used in a python context is run in 'soft' mode;
# upon exiting the context; congregated errors are subsequently raised (if any)
context.starts_with("B").ends_with("z").is_equal_to("Baz").has_length(2) # Ends in a failure.
Will result in the following:
def test_foo(asserto) -> None:
> with asserto("Bar") as context:
E AssertionError: 1 Soft Assertion Failures
E [AssertionError("Length of: 'Bar' was not equal to: 2")]
Asserto
has the ability to assert exceptions are raised on callables
using a simple API.
from asserto import asserto
import typing
def simple_callable(x: int) -> typing.NoReturn:
raise ValueError(x)
def test_exc_handling():
asserto(simple_callable).should_raise(ValueError).when_called_with(25)
Asserto
has the ability to dynamically lookup attributes on any object type. This is
handled using the attr_is(expected)
syntax.
from asserto import asserto
class Foo:
def __init__(self, x) -> None:
self.x = x
def double_x(self) -> int:
return self.x * 2
def test_foo_dynamically() -> None:
# dynamically looking up `x` (attr) or `double_x` bound method & invoking it!
asserto(Foo(10)).x_is(10).double_x_is(20)
Asserto
allows users to easily bolt on their assertion functions.
from asserto import asserto
from asserto import register_assert
@register_assert # Option 1.
def custom_assert(self):
if self.actual != 5:
self.check_should_raise(f"{self.actual} did not equal five!")
register_assert(custom_assert) # Option 2
def test_user_defined_callables() -> None:
asserto(6).custom_assert()
yields the following:
E AssertionError: 6 did not equal five!