3.7 KiB
Clearer Tests Using Nimble Assertions
When code doesn't work the way it's supposed to, unit tests should make it clear exactly what's wrong.
Take the following function which, given a bunch of monkeys, only returns the silly monkeys in the bunch:
public func silliest(monkeys: [Monkey]) -> [Monkey] {
return monkeys.filter { $0.silliness == .verySilly }
}
Now let's say we have a unit test for this function:
func testSilliest_whenMonkeysContainSillyMonkeys_theyreIncludedInTheResult() {
let kiki = Monkey(name: "Kiki", silliness: .extremelySilly)
let carl = Monkey(name: "Carl", silliness: .notSilly)
let jane = Monkey(name: "Jane", silliness: .verySilly)
let sillyMonkeys = silliest([kiki, carl, jane])
XCTAssertTrue(contains(sillyMonkeys, kiki))
}
The test fails with the following failure message:
XCTAssertTrue failed
The failure message leaves a lot to be desired. It leaves us wondering, "OK, so something that should have been true was false--but what?" That confusion slows us down, since we now have to spend time deciphering test code.
Better Failure Messages, Part 1: Manually Providing XCTAssert
Failure Messages
XCTAssert
assertions allow us to specify a failure message of our own, which certainly helps:
func testSilliest_whenMonkeysContainSillyMonkeys_theyreIncludedInTheResult() {
let kiki = Monkey(name: "Kiki", silliness: .extremelySilly)
let carl = Monkey(name: "Carl", silliness: .notSilly)
let jane = Monkey(name: "Jane", silliness: .verySilly)
let sillyMonkeys = silliest([kiki, carl, jane])
- XCTAssertTrue(contains(sillyMonkeys, kiki))
+ XCTAssertTrue(contains(sillyMonkeys, kiki), "Expected sillyMonkeys to contain 'Kiki'")
}
But we have to write our own failure message.
Better Failure Messages, Part 2: Nimble Failure Messages
Nimble makes your test assertions, and their failure messages, easier to read:
func testSilliest_whenMonkeysContainSillyMonkeys_theyreIncludedInTheResult() {
let kiki = Monkey(name: "Kiki", silliness: .extremelySilly)
let carl = Monkey(name: "Carl", silliness: .notSilly)
let jane = Monkey(name: "Jane", silliness: .verySilly)
let sillyMonkeys = silliest([kiki, carl, jane])
- XCTAssertTrue(contains(sillyMonkeys, kiki), "Expected sillyMonkeys to contain 'Kiki'")
+ expect(sillyMonkeys).to(contain(kiki))
}
We don't have to write our own failure message--the one provided by Nimble is already very readable:
expected to contain <Monkey(name: Kiki, sillines: extremelySilly)>,
got <[Monkey(name: Jane, silliness: verySilly)]>
The failure message makes it clear what's wrong: we were expecting kiki
to be included
in the result of silliest()
, but the result only contains jane
. Now that we know
exactly what's wrong, it's easy to fix the issue:
public func silliest(monkeys: [Monkey]) -> [Monkey] {
- return monkeys.filter { $0.silliness == .verySilly }
+ return monkeys.filter { $0.silliness == .verySilly || $0.silliness == .extremelySilly }
}
Nimble provides many different kind of assertions, each with great failure
messages. And unlike XCTAssert
, you don't have to type your own failure message
every time.
For the full list of Nimble assertions, check out the Nimble README. Below is just a sample, to whet your appetite:
expect(1 + 1).to(equal(2))
expect(1.2).to(beCloseTo(1.1, within: 0.1))
expect(3) > 2
expect("seahorse").to(contain("sea"))
expect(["Atlantic", "Pacific"]).toNot(contain("Mississippi"))
expect(ocean.isClean).toEventually(beTruthy())