Hallo keizerinnen en keizers, Leo hier. The topic today is various ways to do equatable in Unit Tests using Swift.

Today we will explore a somewhat common problem when testing code in Swift/iOS development. I can’t stress enough the fact we all should be doing tests, this is a real game changer for any developer.

A long time ago I’ve watched a lecture about code standards and the speaker said something that echoes in me until today:

“What reasoning does someone does to write a line of code and think: “Well I don’t have to test this line.” When you put this into words, sounds weird isn’t it?”

I really hope that all my audience make tests for their code, this leads inevitably to comparisons. Either you use `XCTAssertFalse`, `XCTAssertNil` or any other assertion method eventually you will use some kind of equality. This post is about test equality and how you can compare two things in tests. So be prepared for some nontrivial syntax and various ways to solve the same problem.

Let’s test! But first…

## Painting of The Day

This is a 1664 masterpiece called Crimean Falconer of King John Casimir from the genius Daniel Schultz. Born somewhere around 1615 in Gdańsk (Danzig) in Pomeranian Voivodeship, Polish–Lithuanian Commonwealth, Schultz learned the art of painting from his uncle, Daniel Schultz the Elder, another vital painter, working in his workshop for about five years. After his uncle’s death, he traveled to France and the Netherlands to continue his studies for about three years. The inspirations of Rembrandt and Philippe de Champaigne are visible in his works.

I choose this painting because if you pay attention to the most right kid and the king in the middle, they have a very very similar faces, but they are not equal… are they? As we will talk about equality, an old painting with a family is an amazing example to acknowledge that not everything that looks the same, is the same.

## The problem – Best ways to do Equatable in Unit Tests using Swift

You have a complex type that you want to check its equality with another object in the test suite.

Imagine you have this code within your codebase:

```protocol SimplePrint {
func printAll()
}

struct SimpleManager: SimplePrint {
func printAll() {
print("All")
}
}

struct ComplexType {
let name: String
let action: SimplePrint
}

let complex1 = ComplexType(name: "First", action: SimpleManager())
let complex2 = ComplexType(name: "Second", action: SimpleManager()) ```

What happens if we have to check in the test suit if `complex1` is equal `complex2`?

Well, the answer is you can’t do that because the compiler can’t infer how to compare those two objects, so we need to help him. Let’s start with the most straightforward Xcode recommendation strategy: the `equatable` protocol.

## Solution 1 – Conforming to Equatable

First, you should `import XCTest` and do a little setup to be able to test. Open Xcode Playground if you want to code along, and I recommend that. And let’s dive into the problem:

```class MyTestCase: XCTestCase {

let complex1 = ComplexType(name: "First", action: SimpleManager())
let complex2 = ComplexType(name: "Second", action: SimpleManager())

func testMyCaseTestsNow() {
XCTAssertEqual(complex1, complex1)
}
}

MyTestCase.defaultTestSuite.run()```

You get **Global function `XCTAssertEqual(_:_:_:file:line:)` requires that `ComplexType` conform to `Equatable`**.

So Swift recommends that you use equatable. Let’s conform our ComplexType to Equatable.

```struct ComplexType: Equatable {

let name: String
let action: SimplePrint

static func == (lhs: ComplexType, rhs: ComplexType) -> Bool {
return lhs.name == rhs.name
}
}```

Now you can use `XCTAssertEqual` function on the object. But this could be improved, right?

### Using Identifiable

Ideally, we should only assert equality on objects that we can uniquely identify or all the properties are not relevant to equality (like money, a 5 dollar bill is equal other 5 dollar bill even being different bills). Today is our lucky day! Swift has its own protocol that enforces this, let’s use it:

```struct ComplexType: Equatable, Identifiable {
var id: String
let name: String
let action: SimplePrint

static func == (lhs: ComplexType, rhs: ComplexType) -> Bool {
return lhs.id == rhs.id
}
}```

Now when we compare two `ComplexType` structs we are sure that they are the same. Calling the tests again:

```func testMyCaseTestsNow() {
let complex1 = ComplexType(id: UUID().uuidString, name: "First", action: SimpleManager())
let complex2 = ComplexType(id: UUID().uuidString, name: "Second", action: SimpleManager())

XCTAssertEqual(complex1, complex1)
}```

And this was the first solution!

## Solution 2 – Turn All Properties Into Equatable

Now things begin to be interesting. Now our `ComplexType` has three properties: Two `Strings` ( they are already equatable) and a `SimplePrint` type.

```struct ComplexType: Equatable, Identifiable {
var id: String
let name: String
let action: SimplePrint

static func == (lhs: ComplexType, rhs: ComplexType) -> Bool {
return lhs.id == rhs.id
}
}```

But how can we use equatable inference for `ComplexType`? We need that `SimplePrint` protocol to be equatable too. Like this code below right….? :

`let action: SimplePrint & Equatable`

Not exactly, because the `Equatable` protocol has Self requirements. And the code below shows how Generics come to save the day again:

```struct ComplexType<ActionType: SimplePrint & Equatable>: Identifiable {
var id: String
let name: String
let action: ActionType
}```

But now we have another problem. `SimpleManager` is not `Equatable`. This will force us two choose… If we can turn `SimpleManager` a `Equatable` struct is solved, but if not we can also use conditional protocol conformance, like the example below:

```struct ComplexType<ActionType: SimplePrint>: Identifiable {
var id: String
let name: String
let action: ActionType
}

extension ComplexType: Equatable where ActionType: Equatable {} ```

This way our `ComplexType` can be equatable or not depending on what conforms to `ActionType`. Really amazing, isn’t it?

Now we have to change the tests and create some managers that conform to `Equatable` and `SimplePrint`:

```struct SimpleComparableManager: SimplePrint, Equatable, Identifiable {
var id: String

func printAll() {
print("All")
}
}

class MyTestCase: XCTestCase {

func testMyCaseTestsNow() {
let complex1 = ComplexType(id: UUID().uuidString, name: "First", action: SimpleComparableManager(id: "Manager 1"))
//let complex2 = ComplexType(id: UUID().uuidString, name: "Second", action: SimpleManager())

XCTAssertEqual(complex1, complex1)
}
}```

That was our second possible alternative to solve the unit test equality problem!

## Solution 3 – Use Enums

So if you are sure that you have limited and well-defined implementations of the `SimplePrint` protocol, you can substitute that type by an enum in the `ComplexType`, check the enum below:

```enum PrintManager: Equatable {
case simple(SimpleManager)
case comparable(SimpleComparableManager)

static func == (lhs: PrintManager, rhs: PrintManager) -> Bool {
switch (lhs, rhs) {
case (.simple(_), .simple(_)):
return true
case let (.comparable(a), .comparable(b)):
return a == b
case (.simple(_), _):
return false
case (.comparable(_),_):
return false
}
}
}```

This way you can still force the enum itself to implement the `Equatable` protocol to give us freedom for our types to not implement at all! Now fixing the `ComplexType` and the tests:

```struct ComplexType: Identifiable, Equatable {
var id: String
let name: String
let action: PrintManager
}

class MyTestCase: XCTestCase {

func testMyCaseTestsNow() {
let complex1 = ComplexType(id: UUID().uuidString, name: "First", action: .comparable(SimpleComparableManager(id: "123123")))
//let complex2 = ComplexType(id: UUID().uuidString, name: "Second", action: SimpleManager())

XCTAssertEqual(complex1, complex1)
}
}```

And… Voilà! You have your comparison and the flexibility to your managers not being necessarily equatable. By the way, this is the only way to compare two things that are not `Equatable`, you have to wrap your not `Equatable` Type into `Equatable` one… Or maybe there are other ways!

## Solution 4 – Using XCTAssertIdentical and XCTAssertNotIdentical

For this, you will need to transform your structs into classes. This way you leave behind the value type of your object and embrace the reference type. Enabling us to compare not only values but also memory addresses.

Let’s do the code changes:

```class ComplexType: Identifiable { // now is a class
var id: String
let name: String
let action: SimplePrint

init(id: String, name: String, action: SimplePrint) {
self.id = id
self.name = name
self.action = action
}
}```

We have to add the initializer because we don’t receive a default one from classes. (Well, I know some classes you can create without init but this is a topic for another article).

Now we can compare their identities:

```class MyTestCase: XCTestCase {

func testMyCaseTestsNow() {
let complex1 = ComplexType(id: UUID().uuidString, name: "First", action: SimpleComparableManager(id: "123123"))

XCTAssertIdentical(complex1, complex1)
}
}```

And of course, we have the `nonIdentical` too:

```class MyTestCase: XCTestCase {

func testMyCaseTestsNow() {
let complex1 = ComplexType(id: UUID().uuidString, name: "First", action: SimpleComparableManager(id: "123123"))
let complex2 = ComplexType(id: UUID().uuidString, name: "First", action: SimpleComparableManager(id: "123123"))

XCTAssertNotIdentical(complex1, complex2)
}
}

```

**Important note: When comparing classes with `XCTAssertIdentical` or `XCTAssertNotIdentical` you are just testing if both of the variables point to the same object in the memory. You are not pointing to values here, keep this in mind!

## Solution 5 – The Legendary Triple Equal Identity Operator

Another way to compare pointers in the memory (classes) is using the legendary triple equals identity operator `===`:

```class MyTestCase: XCTestCase {

func testMyCaseTestsNow() {
let complex1 = ComplexType(id: UUID().uuidString, name: "First", action: SimpleComparableManager(id: "123123"))

XCTAssertTrue(complex1 === complex1)
}
}
```

It’s the same result as using `XCTAssertIdentical`.

## Solution 6 – Use ObjectIdentifier

Same as above but using the struct `ObjectIdentifier` to uniquely identify a class instance or meta type.

```class MyTestCase: XCTestCase {

func testMyCaseTestsNow() {
let complex1 = ComplexType(id: UUID().uuidString, name: "First", action: SimpleComparableManager(id: "123123"))

XCTAssertEqual(ObjectIdentifier(complex1), ObjectIdentifier(complex1))
}
}```

And we are done!

## Summary – Best way to do Equatable in Unit Tests in Swift

Today we learn many ways to do object comparison in Swift. Using structs with generics with optional conformance protocol, or enums to wrap the non-equatable content or making it a class and comparing pointers in memory, the most important thing to keep in mind is what makes sense to your codebase. If using structs is fine, so let it be. Now we’ve explored many options for you and I’m sure there are many other ones!

That’s all my people, I hope you liked reading this article as much as I enjoyed writing it. If you want to support this blog you can Buy Me a Coffee or leave a comment saying hello. You can also sponsor posts and I’m open to `freelance writing!` You can reach me on LinkedIn or Twitter and send me an e-mail through the contact page.

Thanks for reading and… That’s all folks.

Credits:

title image