Reputation: 1529
Let's say I have a struct
that conforms to Equatable
for my model, something like this:
struct Model: Equatable {
var a: Int = 0
var b: String = ""
}
func ==(lhs: Model, rhs: Model) -> Bool {
return lhs.a == rhs.a && lhs.b == rhs.b
}
Now I write some unit tests for this. Something like:
func testModelsAreEqual() {
let model1 = Model()
let model2 = Model()
XCTAssertEqual(model1, model2)
}
func testModelsAreNotEqual1() {
let model1 = Model()
var model2 = Model()
model2.b = "hello world"
XCTAssertNotEqual(model1, model2)
}
func testModelsAreNotEqual2() {
let model1 = Model()
var model2 = Model()
model2.a = 1
XCTAssertNotEqual(model1, model2)
}
But how can I write a test that will protect me from the scenario that another property is added to Model
without being added to the memberwise-equality check for ==
like:
struct Model: Equatable {
var a: Int = 0
var b: String = ""
var c: Double = 0
}
func ==(lhs: Model, rhs: Model) -> Bool {
return lhs.a == rhs.a && lhs.b == rhs.b
}
Where obviously my tests will all still pass even though conceptually my Equatable
is broken. Is there a testing strategy I could adopt here that will help alert me to this problem? Is there something I can do with Swift's Mirror
and limited reflection? Perhaps Mirror.children.count
? Or does anyone have a better suggestion?
Upvotes: 1
Views: 706
Reputation: 93161
This is my take:
func testModel3() {
let model1 = Model()
var model2 = Model()
model2.c = 1
model2.p.name = "Jack"
let mirror1 = Mirror(reflecting: model1)
let mirror2 = Mirror(reflecting: model2)
let prop1 = mirror1.children.reduce([String: NSObject]()) {
(var dict, e) in
dict[e.label!] = e.value as? NSObject
return dict
}
let prop2 = mirror2.children.reduce([String: NSObject]()) {
(var dict, e) in
dict[e.label!] = e.value as? NSObject
return dict
}
if model1 == model2 {
XCTAssertEqual(prop1, prop2, "Not really equal")
} else {
XCTAssertNotEqual(prop1, prop2, "Not really diffrent")
}
}
It builds 2 dictionaries with the names & values of all properties in model1
and model2
, then assert if these 2 dictionaries are equal.
Big warning: I have not thoroughly tested this. It worked for the limited number of cases I threw at it. You may have to improvise from here.
Upvotes: 0
Reputation: 1529
After searching for other solutions, I have decided to use reflection for member count to alert me of changes. Here is the test for the example above:
func testModelStillHas2Members() {
XCTAssertEqual(Mirror(reflecting: Model()).children.count, 2, "The member count of Model has changed, please check the `==` implementation to ensure all members are accounted for.")
}
Upvotes: 3