I have 3 methods that are related to a specific class which is defined as follows:
class MyClass: NSObject {
func myMethod() {
methodA()
methodB()
methodC()
}
func methodA() {}
func methodB() {}
func methodC() {}
}
I need to test that myMethod has called all 3 methods by the order they are implemented: methodA then methodB then methodC
to be tested with XCode Unit Tests, regardless of the implementation of these methods, I have created a subclass in the test case that looks like the following:
class ChildClass: MyClass {
var method1CallingDate: Date?
var method2CallingDate: Date?
var method3CallingDate: Date?
override func methodA() {
super.methodA()
method1CallingDate = Date()
}
override func methodB() {
super.methodB()
method2CallingDate = Date()
}
override func methodC() {
super.methodC()
method3CallingDate = Date()
}
}
Now in the test method, I start by calling those 3 methods, then I assert that all three dates are not nil first, then compare them like this:
XCTAssertLessThan(method1CallingDate, method2CallingDate)
XCTAssertLessThan(method2CallingDate, method3CallingDate)
The problem I ran into was that the test sometimes succeeds and sometimes fails, i guess due to Date object is (randomly) the same between 2 of the method calls.
Is there a better way to test the order of calling multiple methods ?
p.s. this is easily done in the Android SDK org.mockito.Mockito.inOrder
First, make a mock object that records the order. No dates, no strings. Just an enumeration.
class MockMyClass: MyClass {
enum invocation {
case methodA
case methodB
case methodC
}
private var invocations: [invocation] = []
override func methodA() {
invocations.append(.methodA)
}
override func methodB() {
invocations.append(.methodB)
}
override func methodC() {
invocations.append(.methodC)
}
func verify(expectedInvocations: [invocation], file: StaticString = #file, line: UInt = #line) {
if invocations != expectedInvocations {
XCTFail("Expected \(expectedInvocations), but got \(invocations)", file: file, line: line)
}
}
}
Then in the test:
mock.verify(expectedInvocations: [.methodA, .methodB, .methodC])
No async waiting. Simple to call. Clear failure messages.
You could do something like this using a String to keep track of the order:
class ChildClass: MyClass {
var order = ""
override func methodA() {
super.methodA()
order = String((order + "A").suffix(3))
}
override func methodB() {
super.methodB()
order = String((order + "B").suffix(3))
}
override func methodC() {
super.methodC()
order = String((order + "C").suffix(3))
}
}
Then, just check that order is "ABC".
Or, if it is valid to call B multiple times between A and C:
class ChildClass: MyClass {
var order = ""
override func methodA() {
super.methodA()
order = order.replacingOccurrences(of: "A", with: "") + "A"
}
override func methodB() {
super.methodB()
order = order.replacingOccurrences(of: "B", with: "") + "B"
}
override func methodC() {
super.methodC()
order = order.replacingOccurrences(of: "C", with: "") + "C"
}
}
Example:
let c = ChildClass()
c.methodA()
c.methodB()
c.methodB()
c.methodC()
print(c.order)
ABC
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With