Skip to content

Instantly share code, notes, and snippets.

@lightsprint09
Created March 14, 2017 07:52
Show Gist options
  • Save lightsprint09/b4c42695d90472dd459f48b34ae11ef9 to your computer and use it in GitHub Desktop.
Save lightsprint09/b4c42695d90472dd459f48b34ae11ef9 to your computer and use it in GitHub Desktop.
struct Train {
let name: String
let date: Date
}
extension Train: Equatable {
static func ==(lhs: Train, rhs: Train) -> Bool {
return lhs.name == rhs.name
}
}
class TrainTest: XCTestCase {
func testEquatableWithDump() {
//Given
let ice = Train(name: "ICE", date: Date(timeIntervalSinceNow: 20))
let ice2 = Train(name: "ICE", date: Date(timeIntervalSinceNow: 30))
//When
AssertEqualWithDump(ice, ice2)
}
}
public func AssertEqualWithDump<T : Equatable>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
guard let lhs = try? expression1(), let rhs = try? expression2() else {
XCTFail()
return
}
if lhs == rhs {
assertDumpsEqual(lhs, rhs, file: file, line: line)
} else {
XCTFail()
}
}
//From https://oleb.net/blog/2017/03/dump-as-equatable-safeguard/
func assertDumpsEqual<T>(_ lhs: @autoclosure () -> T,
_ rhs: @autoclosure () -> T,
file: StaticString = #file, line: UInt = #line) {
XCTAssert(String(dumping: lhs()) == String(dumping: rhs()),
"Expected dumps to be equal.",
file: file, line: line)
}
extension String {
/**
Creates a string from the `dump` output of the
given value.
*/
init<T>(dumping x: T) {
self.init()
dump(x, to: &self)
}
}
@ole
Copy link

ole commented Mar 14, 2017

Thanks for writing it up. Maybe I'm still missing something, but isn't the test wrong as you wrote it? After all, ice and ice2 should not be equal, so asserting that they are doesn't make sense.

The assertion should be XCTAssertNotEqual(ice, ice2). This would be useful as it would actually find the bug. I don't see what assertDumpsEqual gives you over a complete set of test cases (i.e. every permutation of equal/not equal properties) with normal assertions.

E.g. you not only need to test the case you have, but also:

let t1 = Train(name: "A", date: x)
let t2 = Train(name: "B", date: x)
XCTAssertNotEqual(t1, t2)

etc.

And every time you add a new property to the struct, you have to remember to add more test cases. Admittedly, this may be easier to remember than fixing the broken == implementation in the first place because the compiler will tell you if the added property causes the initializers you used in your tests to break – but that would only be the case if the added property has no default value!

@lightsprint09
Copy link
Author

Thats for the detailed reply :)

The test is correct but it should fail. This tests should detect that the implementation is incorrect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment