AssertStep
An AssertStep can be understood as the following function ScenarioContext => Assertion. Its goal is to describe an expectation.
The test engine is responsible to test the validity of the provided Assertion.
When I AssertStep("always true!", _ => GenericEqualityAssertion(true, true))
Equality assertions
Test the equality of two objects using the cats Eq typeclass.
GenericEqualityAssertion compares two values and reports a detailed diff on failure:
AssertStep("names match", sc => {
val name = sc.session.getUnsafe("hero-name")
GenericEqualityAssertion(name, "Batman")
})
CustomMessageEqualityAssertion lets you provide a custom error message when the default diff is not helpful:
AssertStep("DB row exists", sc => {
val count = sc.session.getUnsafe("row-count").toInt
CustomMessageEqualityAssertion(1, count, () => s"Expected exactly 1 row but found $count")
})
Ordering assertions
Compare two values using the cats Order typeclass.
GreaterThanAssertion checks that the actual value is strictly greater:
AssertStep("response time acceptable", sc => {
val elapsed = sc.session.getUnsafe("elapsed-ms").toDouble
GreaterThanAssertion(elapsed, 0.0)
})
LessThanAssertion checks that the actual value is strictly less:
AssertStep("not too slow", sc => {
val elapsed = sc.session.getUnsafe("elapsed-ms").toDouble
LessThanAssertion(elapsed, 5000.0)
})
BetweenAssertion checks that the actual value falls within a range (exclusive bounds):
AssertStep("estimate PI", sc => {
val pi = sc.session.getUnsafe("result").toDouble
BetweenAssertion(3.1, pi, 3.2)
})
Collection assertions
Test the state of a collection of elements.
// Check a collection is empty
CollectionEmptyAssertion(List.empty[String], "heroes")
// Check a collection is not empty
CollectionNotEmptyAssertion(List("Batman", "Superman"), "heroes")
// Check exact size
CollectionSizeAssertion(List("a", "b", "c"), 3, "letters")
String assertions
Assert the content of a String value.
StringContainsAssertion checks that a string contains a given substring:
AssertStep("city name contains 'Gotham'", sc => {
val city = sc.session.getUnsafe("city")
StringContainsAssertion(city, "Gotham")
})
RegexAssertion checks that a string matches a regular expression:
AssertStep("looks like a UUID", sc => {
val id = sc.session.getUnsafe("id")
RegexAssertion(id, """[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}""".r)
})
Composing assertions
Assertions can be composed using and and or:
AssertStep("value in range", sc => {
val v = sc.session.getUnsafe("value").toDouble
GreaterThanAssertion(v, 0.0) and LessThanAssertion(v, 100.0)
})
Full example
Below is a complete example showing how to integrate an assertion into a scenario.
When I EffectStep.fromSync(
title = "estimate PI",
effect = scenarioContext => scenarioContext.session.addValueUnsafe("result", piComputation())
)
Then assert AssertStep(
title = "check estimate",
action = scenarioContext => Assertion.either {
scenarioContext.session.get("result").map(r => BetweenAssertion(3.1, r.toDouble, 3.2))
}
)
This is rather low level therefore you should not write your steps like that directly inside the DSL but hide them behind functions with appropriate names.
Fortunately a bunch of built-in steps and primitive building blocks are already available for you.
For advanced users: it is also possible to write custom wrapper steps by implementing WrapperStep. See the Wrapper Steps section in the DSL reference.