Here on mokacoding we've talked a number of times about the benefits of the xSpec style when writing unit tests.
There is a catch though. Because XCTest does not provide a DSL for xSpec style testing we need to use a third party library to write in this wonderful style. The best xSpec frameworks for Objective-C are, in alphabetical order, Cedar, Kiwi, and Specta, while on Swift Quick is the one with the biggest traction.
Unfortunately the iOS world doesn't have a strong testing culture, yet, and is not uncommon to join a team where unit testing had to be introduced from scratch.
In such case dropping a framework combo like Specta + Expecta + OCMock might be too much for the team to handle in one go. It might be better to stick with XCTest and work on the team testing workflow instead.
If you decide to go with this approach you'll soon discover two things:
- The xUnit style is not as bad as you remembered.
- Everybody only uses
XCTAssert
andXCTAssertEquals
.
That's the thing, the assertion provided by XCTest
are not powerful enough, and way to verbose.
Let me introduce you to Nimble a matcher framework for Swift (and Objective-C) that you can easily integrate in your XCTestCase
s to have a way nicer and easy to write syntax.
This is how some usual assertion look when written using Nimble
XCTAssertEqual(anInt, 42)
expect(anInt) == 42
XCTAssert(aBool)
expect(aBool).to(beTrue())
XCTAssertFalse(anotherBool)
expect(anotherBool).to(beFalsy())
XCTAssertEqual(aString, "expected value")
expect(aString) == "expected value"
They read quite better, and in particular the relationship between actual and expected value is explicit. Plus, how neat is it to use ==
to test for equality? 😎
And it doesn't end here, Nimble provide syntactic candies like:
Negative forms
expect(batman.name).toNot(equal("Peter Parker"))
expect(ironman.name).notTo(equal("Barry Allen"))
expect(greenArrow.name) != "Matt Murdok"
Math comparisons
expect(actual).to(beLessThan(expected))
expect(actual) < expected
expect(actual).to(beLessThanOrEqualTo(expected))
expect(actual) <= expected
expect(actual).to(beGreaterThan(expected))
expect(actual) > expected
expect(actual).to(beGreaterThanOrEqualTo(expected))
expect(actual) >= expected
Range comparisons
expect(10.01).to(beCloseTo(10, within: 0.1))
expect(actual) ≈ (expected, delta)
expect(actual) == expected ± delta
Async expectations
expect(systemUnderTest.someState).toEventually(beTruthy(), timeout: 3)
Swift 2 error handling
expect{ try somethingThatThrows() }.to(throwError())
You can learn about all the awesome matchers that Nimble provides out of the box in the README, and if you need more expressive power you can even write your own.
Conclusion
Nimble is a great Swift matcher framework. Integrating it with vanilla XCTest
suites is easy and frictionless.
By providing an easy to use and powerful syntax for expectations you can help your team adopt unit testing and be productive, with a very smooth learning curve.
If you want some alternatives, have a look to Expecta and OCHamcrest.
Want to share your experience with Nimble or with introducing testing and TDD is your workspace? Tweet me @mokagio, or leave a comment below.
Leave the codebase better than you found it.