- Example — a condition, a check, a test. Follows RSpec naming. See Specification by Example.
- Example Group — a group of examples.
It is important to understand that specifications don’t have a notion of tests per se. xUnit tests are broken into two concepts: actions and checks.
@Test fun `increment changes value`() {
// This is an action.
counter.increment()
// This is a check.
assertThat(counter.current()).isEqual(1)
}
context("increment") {
// This is an action.
beforeEach {
counter.increment()
}
// This is a check.
it("changes value") {
assertThat(counter.current()).isEqual(1)
}
}
Take a closer look again — tests are trying to be two things at once, specifications make them atomic and dedicated. When this idea clicks — there is no way back to xUnit.
Specifications are declared as Spec
subclasses.
Spec
receives a lambda on a top-level Example Group which allows to declare
further Example Groups and Examples.
class CounterSpec : Spec({
val counter by memoized { Counter.Impl() }
it("contains default value") {
assertThat(counter.current()).isZero()
}
})
Example Groups can declare Examples, Example Groups and a bit more. Examples cannot declare anything.
Declares an Example Group.
context("nothing") {
it("does not change value") {
assertThat(counter.current()).isEqual(0)
}
}
describe
is a context
synonym. Use it for grouping context
declarations
when necessary.
Declares an Example.
it("changes value") {
assertThat(counter.current()).isEqual(1)
}
Focuses an Example Group or an Example. Focusing means executing focused entries and nothing else.
// Skipped.
it("tracks analytics") {
verify(env.analytics).trackEvent(Analytics.Event.CounterIncrement)
}
// Executed.
fit("changes value") {
assertThat(counter.current()).isEqual(1)
}
Excludes an Example Group or an Example. Excluding means skipping excluded entries.
// Executed.
it("tracks analytics") {
verify(env.analytics).trackEvent(Analytics.Event.CounterIncrement)
}
// Skipped.
xit("changes value") {
assertThat(counter.current()).isEqual(1)
}
Declares an action executed before (beforeEach
) or after (afterEach
) an example.
beforeEach {
counter.increment()
}
Declares a special delegate. See RSpec let
.
- The delegated object is created on the first access.
- The object is cached during an example execution.
- The object is removed after the example execution.
val counter by memoized { Counter.Impl() }
This is a direct equivalent of the following xUnit declaration.
var counter: Counter? = null
@BeforeEach fun setUp() {
counter = Counter.Impl()
}
@AfterEach fun tearDown() {
counter = null
}