View Source TypeCheck.ExUnit (TypeCheck v0.12.0)
Provides macros for 'spectests': spec-automated property-testing.
The core macro exposed by this module is spectest/2
, which
will will check for all function-specs in the given module,
whether those functions correctly follow the spec.
To use this functionality, add use TypeCheck.ExUnit
to your testing module.
Currently, spectesting uses StreamData
under the hood.
This means that to use the spectest
functionality,
you need to add the :stream_data
dependency to your application
(it is an optional dependency of TypeCheck
.)
In the future, support for other property-generating libraries might be added.
what-is-a-spectest
What is a spectest?
A 'function-specification test' is a property-based test in which we check whether the function adheres to its invariants (also known as the function's contract or preconditions and postconditions).
We generate a large amount of possible function inputs, and for each of these, check whether the function:
- Does not raise an exception.
- Returns a result that type-checks against the spec's return-type. (To be precise, if an incorrect result is returned, the function is wrapped in will end up raising an exception for this.)
While @spec!
s themselves ensure that callers do not mis-use your function,
a spectest
ensures¹ that the function itself is working correctly.
Spectests are given its own test-category in ExUnit, for easier recognition (Just like 'doctests' and 'properties' are different from normal tests, so are 'spectests'.)
¹: Because of the nature of property-based testing, we can never know for 100% sure that a function is correct. However, with every new randomly-generated test-case, the level of confidence grows a little. So while we can never by fully sure, we are able to get asymptotically close to it.
Link to this section Summary
Functions
Sets up a testing module for spectesting.
Tests the functions in module
against their @spec!
s.
Link to this section Functions
Sets up a testing module for spectesting.
Not normally invoked directly, but rather by calling use TypeCheck.ExUnit
.
Currently does not accept any options, but this might change in the future.
Tests the functions in module
against their @spec!
s.
spectest
will look at all functions which have a TypeCheck spec in module
,
and will for each of them run a 'spectest'.
See the module documentation for more information on spectests in general.
examples
Examples
defmodule MyModuleTest do
use ExUnit.Case, async: true
use TypeCheck.ExUnit
# Test all functions that have `@spec!`s in `MyModule`
spectest MyModule
# Test all functions that have `@spec!`s in `MyOtherModule`,
# except `MyOtherModule.bar/2` and `MyOtherModule.baz/0`
spectest MyOtherModule, except: [{:bar, 2}, {:baz, 0}]
# Test only `OneMoreModule.foo/2` and `MyOtherModule.qux/0`
spectest OneMoreModule, only: [{:foo, 2}, {:qux, 0}]
end
options
Options
:except
:only
:initial_seed
:generator
Except and Only
By default, all functions in the module (that have an associated @spec!
) will be tested.
If any of them need to be skipped, you can add them as a list of {name, arity}
-pairs under except:
.
If instead of excluding a few functions, you want to only test a small subset of functions, you can add them as {name, arity}
-pairs under only:
.
Initial seed
The :initial_seed
-option can be used to seed the property-generation.
It expects an integer value.
This option is passed on to the generator automatically (without requiring the usage of generator-specific options).
By default, the seed of the ExUnit configuration is used (which by default differs every test run).
Generator
The generator:
option expects either the name of a property-testing library, or a {name, options}
-tuple.
(If only the name is specified, this is a shorthand for {Name, []}
).
For now, only StreamData
is supported, and this is its default value. If you want to pass extra options to the library, the notation {StreamData, list_of_options}
can be passed.
For the list of options supported by StreamData, see StreamData.check_all/3
.