From the blog

XCTest and Optional Unwrapping

computer with typing image

XCTest is the default test harness on iOS and Apple’s other platforms. It provides support for organizing test cases and asserting expectations in your application code, and reporting the status of those expectations. It’s not as fancy as some of the BDD frameworks like Quick and Cedar, but it has gotten much better than it used to be, and is my preferred test framework these days.

The Problem

One place where the XCTest assertion utilities fall a bit short has been with managing Optional variables in Swift. XCTAssertNotNil doesn’t provide any mechanism for unwrapping variables, easily leading to assertion checks like this:

The asserts following XCTAssertNotNil are where things can get ugly. It’s very common for ! usage to sneak in. Force-unwrapping a nil value will crash your unit tests, and the remaining unit tests will not be run or reported to CI.

The Solution

A nice solution is possible, due to an often-overlooked feature of XCTestCase. If the test function is marked with throws, any thrown exception will cause the test to fail. We can use this to fail our tests using normal Swift flow control mechanisms:

This helps clean up our nil check by using more typical Swift Optional expressions. This will stop the test if it encounters nil, and allows the remainder of the test to use the unwrapped value. This is a good start, except XCTestCase doesn’t report the error location correctly. If the test function throws, Xcode points to the test function as the source of the failure, not the line that threw the exception. But not to worry: this is easy to clean up with a little wrapper that uses the #file and #line default values.

Now we have a nice Swifty test helper to manage nil checks. I hope this helps clean up your test code. And remember, ! is rarely a good answer, even in tests!

Feel free to check out other posts we’ve written or get in touch to discuss how we can work together!

1 Comment

  1. Using throws on the test method is a good idea. I have been using another little-known feature of XCTestCase combined with the dreaded postfix !:

    In your setup method (or any test method) you can say continueAfterFailure = false and then know that any assertion failure will interrupt the test. I find this is usually what I want anyway; why continue asserting if things have gone sideways?

    With that in place, I feel more confident using ! to unwrap things after an XCTAssertNotNil.

Leave a Reply

Your email address will not be published. Required fields are marked *