Testing¶
didactic.api.testing ¶
Test helpers for didactic-using projects.
Not imported by didactic automatically. Reach for it as
from didactic.api import testing or import didactic.testing as dxt
inside your test suite.
Public surface
verify_iso Property-test that an Iso satisfies its round-trip laws over a Hypothesis strategy. check_lens_laws Property-test that a Lens satisfies the GetPut and PutGet laws.
Both helpers are thin wrappers around hypothesis.given; they exist
so test files don't have to import Hypothesis directly when all they
want is a one-liner law check.
See Also
didactic.lenses._lens : the Lens / Iso / Mapping classes.
verify_iso ¶
verify_iso(
iso: Iso[A, A],
strategy: SearchStrategy[A],
*,
max_examples: int = 100,
) -> None
Property-test that iso is a true bijection on its source class.
Runs max_examples Hypothesis-generated values through
iso.backward(iso.forward(x)) == x, asserting equality on every
sample. The complementary direction iso.forward(iso.backward(y))
cannot be exercised against a generated input without a generator
over the target's value space; verifying both directions requires
two strategies and is left to
check_lens_laws
or hand-written tests.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iso
|
Iso[A, A]
|
An Iso instance to verify. |
required |
strategy
|
SearchStrategy[A]
|
A Hypothesis strategy producing values of the source class. |
required |
max_examples
|
int
|
Number of samples to generate. Default |
100
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If any sample fails the round-trip law. |
Examples:
>>> import didactic.api as dx
>>> from didactic.testing import verify_iso
>>> from hypothesis import strategies as st
>>>
>>> class User(dx.Model):
... id: str
... bio: str = ""
>>>
>>> class Identity(dx.Iso[User, User]):
... def forward(self, u: User) -> User:
... return u
...
... def backward(self, u: User) -> User:
... return u
>>>
>>> users = st.builds(User, id=st.text(), bio=st.text())
>>> verify_iso(Identity(), users)
check_lens_laws ¶
check_lens_laws(
lens: Lens[A, B],
strategy: SearchStrategy[A],
*,
max_examples: int = 100,
) -> None
Property-test that lens satisfies the GetPut law.
The GetPut law (backward(*forward(a)) == a) is the most useful
invariant; PutGet requires generating valid B values plus
matching complements, which requires a second strategy and a
knowledge of the lens's complement type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lens
|
Lens[A, B]
|
A Lens instance to verify. |
required |
strategy
|
SearchStrategy[A]
|
A Hypothesis strategy producing values of the source class. |
required |
max_examples
|
int
|
Number of samples to generate. Default |
100
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If any sample violates GetPut. |
verify_mapping ¶
verify_mapping(
mapping: Mapping[A, B],
strategy: SearchStrategy[A],
*,
max_examples: int = 100,
) -> None
Property-test that a Mapping is a function.
The check runs the mapping on every generated input and asserts that calling it twice on the same input produces equal outputs; the absence of side effects is the property mappings promise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mapping
|
Mapping[A, B]
|
A Mapping instance. |
required |
strategy
|
SearchStrategy[A]
|
Hypothesis strategy over the source class. |
required |
max_examples
|
int
|
Sample count. Default |
100
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If a sample produces different outputs on two calls. |
verify_iso_inverse ¶
verify_iso_inverse(iso: Iso[A, B]) -> None
Verify that iso.inverse().inverse() == iso (symmetry of inverse).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iso
|
Iso[A, B]
|
An Iso instance. |
required |
Raises:
| Type | Description |
|---|---|
AssertionError
|
If the iso's double-inverse is not the same iso (by identity or by structural fingerprint of forward/backward outputs on a sample). |
verify_lens_composition ¶
verify_lens_composition(
lens_ab: Mapping[A, B],
lens_bc: Mapping[B, C],
strategy: SearchStrategy[A],
*,
max_examples: int = 100,
) -> None
Verify that (lens_ab >> lens_bc)(x) == lens_bc(lens_ab(x)).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lens_ab
|
Mapping[A, B]
|
A lens / mapping from |
required |
lens_bc
|
Mapping[B, C]
|
A lens / mapping from |
required |
strategy
|
SearchStrategy[A]
|
Hypothesis strategy over the source class |
required |
max_examples
|
int
|
Sample count. Default |
100
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If the composed lens disagrees with manual chaining on any sample. |
verify_migration_round_trip ¶
verify_migration_round_trip(
iso: Iso[A, A],
source_strategy: SearchStrategy[A],
*,
max_examples: int = 100,
) -> None
Verify that an Iso preserves information across a migration round trip.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iso
|
Iso[A, A]
|
An Iso meant to be used as a migration; this
helper enforces that |
required |
source_strategy
|
SearchStrategy[A]
|
Hypothesis strategy over the source Model class. |
required |
max_examples
|
int
|
Sample count. Default |
100
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If any sample loses information. |