Skip to content

an equality assertion for swift tests similar to XCTAssertEqual but using reflection rather than an equals function.

License

Notifications You must be signed in to change notification settings

motocodeltd/MCAssertReflectiveEqual

Repository files navigation

MCAssertReflectiveEqual

CI Status Version License Platform

MCAssertReflectiveEqual is a function that can be used to write swift test assertions. It works very similarly to XCTest's XCTAssertEqual but doesn't require Equatable items and uses reflection instead. Therefore you don't need to write neither equals functions that your production code does not require, nor assert multiple individual fields making tests a chore.

MCAssertReflectiveEquals works on primitives, structs, classes and enums. It gives you a nice error message when items do not match. It deeply compares items and handles recursive loops (A -> B -> A, where A & B are objects and -> is a references). It just makes tests easier.

The development of MCAssertReflectiveEqual is described here.

Example

import XCTest
import MCAssertReflectiveEqual

private class ClassWithVal {
    var val: Int
        
    init(_ val: Int) {
        self.val = val
    }
}

class ClassWithValTest : XCTestCase {

    func testAreEqual() {
        let expected = ClassWithVal(1)
        let actual = ClassWithVal(1)
    
        MCAssertReflectiveEqual(expected, actual) 
        MCAssertReflectiveEqual([expected], [actual])
    
        MCAssertReflectiveEqual(expected, ClassWithVal(5)) //fails
    }

}

Custom Matchers

Sometimes simple reflective matching is not good enough. Imagine a complex data structure that contains a geographical coordinate, a CLLocation. We may not be interested that our expected value is identical to the value produced by the system under test, only that they are close enough. Here's how we go about that:

class FavouriteLocation {
    let user: String
    let location: CLLocation
    
    init(user: String, location: CLLocation) {
        self.user = user
        self.location = location
    }
}
    
let camdenTown = CLLocation(latitude: 51.5390, longitude: 0.1426)
    
let closeToCamdenTown = CLLocation(latitude: 51.5391, longitude: 0.1427)
    
let matcher = matcherFor(CLLocation.self, { (expected, actual) in
                    return expected.distance(from: actual) < 100 //close enough
              }) 
    
MCAssertReflectiveEqual(FavouriteLocation(