Describe Objects upon Failure

Wouldn’t it be nice if we had assertions that came with descriptive messages? The assertions we’ve seen so far can only say that they failed, but they can’t tell us why. But there are some assertions that describe objects. We’ll also look at how to customize the way objects describe themselves in these messages.

Here’s an assertion to confirm that an optional value is nil. Add this test and give it a run:

AssertYourself/AssertYourselfTests/AssertYourselfTests.swift
 func​ ​test_assertNil​() {
 let​ optionalValue: ​Int​? = 123
 XCTAssertNil​(optionalValue)
 }

This is the first assertion that gives us more information upon failure:

 XCTAssertNil failed: "123" -

Instead of nil, we got "123". But why is it in quotes when the type is an optional integer with value 123? That’s the way XCTest reports strings, and assertions ask objects to describe themselves as strings. We can see this better with a struct instead of an Int:

AssertYourself/AssertYourselfTests/AssertYourselfTests.swift
 struct​ ​SimpleStruct​ {
 let​ x: ​Int
 let​ y: ​Int
 }
 
 func​ ​test_assertNil_withSimpleStruct​() {
 let​ optionalValue: ​SimpleStruct​? = ​SimpleStruct​(x: 1, y: 2)
 XCTAssertNil​(optionalValue)
 }

Running this test gives us this message:

 XCTAssertNil failed: "SimpleStruct(x: 1, y: 2)" -

That’s pretty readable for a simple struct. But some types have complicated descriptions. This can make failure messages hard to read. We can control how a type describes itself by making it conform to CustomStringConvertible.

Here’s a structure that is identical to the previous one, but it adds the protocol to give itself a custom description:

AssertYourself/AssertYourselfTests/AssertYourselfTests.swift
 struct​ ​StructWithDescription​: ​CustomStringConvertible​ {
 let​ x: ​Int
 let​ y: ​Int
 
 var​ description: ​String​ { ​"(​​\(​x​)​​, ​​\(​y​)​​)"​ }
 }
 
 func​ ​test_assertNil_withSelfDescribingType​() {
 let​ optionalValue: ​StructWithDescription​? =
 StructWithDescription​(x: 1, y: 2)
 XCTAssertNil​(optionalValue)
 }

Running this test gives us the following simplified failure message:

 XCTAssertNil failed: "(1, 2)" -

XCTAssertNil is one assertion that gives more information. That’s because it takes an object instead of a Boolean value. The assertions for equality also give more information, and we’ll look at them next.

Even in the cases where we provide our own descriptive messages, it’s good to have an option to simplify the output. Keep CustomStringConvertible in your tool belt.