Abstract Types
July 22, 2021 ยท View on GitHub
Most built-in structures have abstract types for you to plug in your own types.
Their names are consistent and match the following:
| Type | Desc |
|---|---|
F[_] | The context in which test execution is performed. By default, this is the built-in type alias Id; for asynchronous tests, scala.concurrent.Future. |
R | Reference. (optional) Some kind of arbitrary (non-strict) data that is available to all parts of the test. It can be used to perform actions or make observations. |
O | Observation. (optional) An immutable snapshot of the stateful world that captures anything relevant to the test. |
S | State for testing. (optional) Data created and updated by the test. Used to keep track of expectations about the test subject. This is not the mutable/stateful test subject; this is immutable, and updated by test Actions. |
E | Error. Representation of assertion failure or exceptions. By default, this is String. |
Example
As an example, if you were testing a database you might have the following:
R=java.sql.Connection- A connection to the subject database.O=Vector[String]- All user names in the DB. The result ofselect name from user.S=Int- The expected number of user names.- An action called
addUserthat issues ainsert ? into userand setsS := S + 1. - An invariant that specifies that the number of real users
(_: O).lengthmatchesS.
Primary Types
| Type | Desc |
|---|---|
Actions[F[_], R, O, S, E] | Zero or more actions that affect the impure world and possibly update test state expectations. Executed one at a time. |
Invariants[-O, -S, E] | Zero or more properties that should always be true. |
Points[-O, -S, E] | Zero or more assertions at a single Point in time. Eg. x is 7. |
Arounds[-O, -S, E] | Zero or more assertions Around a period of time. Eg. x was 7, x increased by 2. |
Dsl[F[_], R, O, S, E] | Provides you with a library of functions. See DSL.md. |
ROS[+R, +O, +S] | Same as a (R,O,S) tuple except instead of _1, _2, _3 it has ref, obs, state. |
OS[+O, +S] | Same as a (O,S) tuple except instead of _1, _2 it has obs, state. |
Name | A lazy String that specifies the name of an action or assertion. |
NameFn[-A] | A function from Option[A] to a Name.Think of it as a Name that becomes more detailed when an A becomes available.Example: It could return "Check counter" on None, and "Check counter is 7" on Some(7). |
Report[+E] | Result of test execution. You'll often just call .assert() on this to assert that the test passed. |
Using the above, you create the content of your tests. In order to run tests, you combine data as follows:
Example:
class Ref
class Obs(ref: Ref)
val dsl = Dsl[Ref, Obs, Int]
val action = dsl.emptyAction // Actions [Id, Ref, Obs, Int, String]
val invariants = dsl.emptyInvariant // Invariants [Obs, Int, String]
Plan(action, invariants) // Plan [Id, Ref, Obs, Int, String]
.withInitialState(123) // PlanWithInitialState[Id, Ref, Obs, Int, String]
.test(Observer(new Obs(_))) // TestWithInitialState[Id, Ref, Obs, Int, String]
.run(new Ref) // Id[Report[String]] = Report[String]
Secondary Types
| Type | Desc |
|---|---|
Display[A] | Typeclass used by Dsl assertions to turn expectation and actual values into Strings for display. (For humans, unlike common Show[A].) |
Equal[A] | Typeclass used by Dsl assertions for equality checking. Implicit conversions exist from:
|
ExecutionModel[F[_]] | Typeclass required to run tests in custom contexts. |
Observer[-R, +O, +E] | Creates observations. As indicate by type variance, ref comes in, observation or error come out. |
Or[+A,+B] | Disjunction. Internal replacement for stdlib's atrocious Either. Implicit conversions exist from:
|
Attempt[+E] | Turns a Throwable into an E. |
Report.AssertionSettings | Typeclass that specifies how to display pass/fail results on a Report. |