effect-ts-laws v1.2.19
A library for law testing. Test @effect/typeclass and schema laws using fast-check. The typeclass laws implemented are listed here.
Read on for the project introduction or jump to:
About
Synopsis
Testing Typeclass Laws on Option<A>
testTypeClassLaws
will find the correct typeclass laws and test them. To define the tests required
for the Option
datatype, for example, we need to:
- Provide a function to build an
Equivalence<Option<A>>
from anEquivalence<A>
.- Thankfully,
effect-ts
has such a function in theOption
module called getEquivalence.
- Thankfully,
- Provide the same for arbitraries.
effect-ts-laws
exports an option function. It takes anArbitrary<A>
and return anArbitrary<Option<A>>
.
- List all instances for the datatype by their typeclass name.
- Note in the code below some instances, for example
Order
, are built from the instance of the underlying type. Theeffect-ts-laws
export monoOrder provides this for theOrder
typeclass.
- Note in the code below some instances, for example
The Option
typeclass law test:
import {
Alternative,
Applicative,
Foldable,
getOptionalMonoid,
Monad,
Traversable
} from '@effect/typeclass/data/Option'
import {Option as OP} from 'effect'
import {monoEquivalence, monoOrder, monoSemigroup, option} from 'effect-ts-laws'
import {testTypeclassLaws} from 'effect-ts-laws/vitest'
import {OptionTypeLambda} from 'effect/Option'
describe('@effect/typeclass/data/Option', () => {
testTypeclassLaws<OptionTypeLambda>({
getEquivalence: OP.getEquivalence,
getArbitrary: option,
})({
Alternative,
Applicative,
Equivalence: OP.getEquivalence(monoEquivalence),
Foldable,
Monad,
Monoid: getOptionalMonoid(monoSemigroup),
Order: OP.getOrder(monoOrder),
Traversable,
})
})
What do we get in return to our investment in the three steps above and in the added maintenance costs of this tiny, easy to maintain test?
Good coverage for a freight train full of fault models. Vitest reporter showing
test results for the seventy one typeclass laws relevant to the effect-ts Option
datatype as defined in the test above:
Testing Typeclass Laws on a New Datatype
You wrote a new datatype: MyTuple
, and an instance of the effect-ts
Covariant
typeclass. Lets test it for free:
import {Covariant as CO} from '@effect/typeclass'
import {Array as AR} from 'effect'
import {dual} from 'effect/Function'
import {TypeLambda} from 'effect/HKT'
import fc from 'fast-check'
import {testTypeclassLaws} from 'effect-ts-laws/vitest'
describe('MyTuple', () => {
type MyTuple<A> = [A]
interface MyTupleTypeLambda extends TypeLambda {
readonly type: MyTuple<this['Target']>
}
const map: CO.Covariant<MyTupleTypeLambda>['map'] = dual(
2,
<A, B>([a]: MyTuple<A>, ab: (a: A) => B): MyTuple<B> => [ab(a)],
)
const Covariant: CO.Covariant<MyTupleTypeLambda> = {
imap: CO.imap<MyTupleTypeLambda>(map),
map,
}
testTypeclassLaws<MyTupleTypeLambda>({
getEquivalence: AR.getEquivalence,
getArbitrary: fc.tuple,
})({Covariant})
})
fast-check
will try to find a counterexample that breaks the laws. Because
it is quite impossible to find one in this case you should see:
Above you see that eight typeclass laws that were tested:
- Covariant identity and composition laws.
count = 2
- Because Covariant extends Invariant, the typeclass
laws of identity and composition of this typeclass are tested.
count = 2 + 2
- effect-ts lets you compose a pair of Invariants into a new
Invariant. There are fault models that will only be covered if we
test such composed instances. To cover these fault models, the
instance under test is composed with the
Option
Invariant instance and run through the identity and composition laws.count = 2 + 2 + 2
- effect-ts lets you compose a pair of Invariants into a new
Invariant. There are fault models that will only be covered if we
test such composed instances. To cover these fault models, the
instance under test is composed with the
- effect-ts lets you compose Covariants as well. The instance under
test is composed with the
Option
Covariant instance and run through the identity and composition laws.count = 2 + 2 + 2 + 2
- Because Covariant extends Invariant, the typeclass
laws of identity and composition of this typeclass are tested.
Overview
Law testing is property
testing, except the properties
are well known laws. Besides being famous, the laws included here were chosen
because they catch bugs efficiently . If you can identify the laws that should
govern your code, then effect-ts-laws
will help you test them.
For example when implementing instances of effect-ts typeclasses for your
datatype, they must be bound by their
typeclass laws.
effect-ts-laws
exports ready-made tests for these, and with very little work
they can be added to your test suite to reduce the risk your customizations are
unlawful.
Features:
- Laws
- Typeclass laws for
effect-ts
typeclasses - Encode/decode laws and Equivalence laws for effect/Schema
effect-ts
datatype typeclass law tests to serve as self-test, demo, and to help this remarkable project. See status for details on what is ready.
- Typeclass laws for
- Law testing infrastructure
fast-check
arbitraries for effect datatypes- typeclass instances and
typeclass law tests
for the
fast-check
Arbitrary type.
- Randomness. Uses
fast-check
property testing. For parameterized type typeclass laws, all functions are randomly generated as well. - Minimal work to test instances for your own datatype: it can all be
done with single function that takes the instances under test and
a pair of functions:
getEquivalence
andgetArbitrary
.- Meaningful test coverage improvement for the price of writing two functions. You probably have them somewhere already.
Project
Play
You can run the project tests online at any of these online sandboxes by opening
a terminal and calling pnpm install && pnpm test-run
. pnpm coverage
will give
you the always 100% coverage report.
- StackBlitz. Note coverage does not work on StackBlitz.
- replit requires you fork
the repository first by clicking the green
Fork
button. - CodeSandbox.
The full self-test suite will run in less than 10 seconds on an average desktop, but will take a minute or two to run on the free tiers of the services above.
Status
This matrix shows data-types (in columns) vs. typeclass law tests (in rows). Each intersection of datatype and typeclass can be either: ready (✅), not ready (❌), or not relevant (☐).
Click a datatype (in column header) to open its source code in the effect-ts
project. Click a typeclass name (in row header) to open its laws as defined in
effect-ts-laws
.
More Information
- User guide.
- API documentation.
- Catalog of laws.
- Status of effect.ts datatype tests.
README
for the arbitraries exported.README
for the law module.README
at the laws for typeclasses on concrete types.README
at the laws for typeclasses on parameterized types.
Roadmap
- Laws
- Sink Contravariant laws.
- More datatypes.
- Relational laws.
- Functional laws.
- Harness
- Pretty print counterexamples. Allow using exception throwing test code+ validation code returning Either instead of boolean for Law.predicate.
- API should let you use any catalog.
- Composition
- Test composition flipped.
- Nest three levels.
- Brand composition: refine(b₂) ∘ refine(b₁) = refine.all(b₁, b₂).
- Arbitraries
oneof
arbitrary chosen from built-in instances.- Schema arbitrary.
See Also
Based On
- fp-ts-laws by Giulio Canti
- Scala's Discipline
- All errors, bugs and misunderstandings are 100% original work.
3 months ago
3 months ago
3 months ago
4 months ago
4 months ago
4 months ago
4 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago