How to test equality of Swift enums with associated values

Swift 4.1+

As @jedwidz has helpfully pointed out, from Swift 4.1 (due to SE-0185, Swift also supports synthesizing Equatable and Hashable for enums with associated values.

So if you're on Swift 4.1 or newer, the following will automatically synthesize the necessary methods such that XCTAssert(t1 == t2) works. The key is to add the Equatable protocol to your enum.

enum SimpleToken: Equatable {
    case Name(String)
    case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)

Before Swift 4.1

As others have noted, Swift doesn't synthesize the necessary equality operators automatically. Let me propose a cleaner (IMHO) implementation, though:

enum SimpleToken: Equatable {
    case Name(String)
    case Number(Int)
}

public func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
    switch (lhs, rhs) {
    case let (.Name(a),   .Name(b)),
         let (.Number(a), .Number(b)):
      return a == b
    default:
      return false
    }
}

It's far from ideal — there's a lot of repetition — but at least you don't need to do nested switches with if-statements inside.


Implementing Equatable is an overkill IMHO. Imagine you have complicated and large enum with many cases and many different parameters. These parameters will all have to have Equatable implemented, too. Furthermore, who said you compare enum cases on all-or-nothing basis? How about if you are testing value and have stubbed only one particular enum parameter? I would strongly suggest simple approach, like:

if case .NotRecognized = error {
    // Success
} else {
    XCTFail("wrong error")
}

... or in case of parameter evaluation:

if case .Unauthorized401(_, let response, _) = networkError {
    XCTAssertEqual(response.statusCode, 401)
} else {
    XCTFail("Unauthorized401 was expected")
}

Find more elaborate description here: https://mdcdeveloper.wordpress.com/2016/12/16/unit-testing-swift-enums/

Tags:

Swift