I am currently writing a test for a bug I've encountered, where the order of calls in the production code is incorrect, leading to a potential race condition.
What is the cleanest way to check the order of calls from the test code, using XCTest?
In OCMock/Objective-C we had setExpectationOrderMatters, as per this question. However I am not aware of similar functionality available in XCTest/Swift due to dynamic/static language differences.
Let's say we want to mock this protocol:
protocol Thing {
func methodA()
func methodB()
}
Here's a mock that doesn't just record call counts of individual methods. It records invocation order:
class MockThing: Thing {
enum invocation {
case methodA
case methodB
}
private var invocations: [invocation] = []
func methodA() {
invocations.append(.methodA)
}
func methodB() {
invocations.append(.methodB)
}
func verify(expectedInvocations: [invocation], file: StaticString = #file, line: UInt = #line) {
if invocations != expectedInvocations {
XCTFail("Expected \(expectedInvocations) but got \(invocations)", file: file, line: line)
}
}
}
This supports test assertions like:
mock.verify(expectedInvocations: [.methodA, .methodB])
Related
I'm drawing a blank for some reason.. If I want to make a bunch of objects from a class, but I want each instance to have its own unique implementation of a certain method, how would I do this?
For example:
class MyClass {
var name: String
func doSomething() {
// Each object would have custom implementation of this method, here.
}
}
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method? I'm trying to figure out the correct or "Swiftly" way to do this. I'm also thinking along the lines of something with protocols, but I can't seem to figure out how to go about this.
I think there're many ways to do it.
In case of Base class + some sub-classes (e.g. Animal, subclassed by Dog, Cat, etc), you can do this:
First of all it's a good idea to define a protocol:
protocol MyProtocol {
func doSomething()
}
Also provide a default implementation, which throws a fatal error if a class doesn't override that method:
extension MyProtocol {
func doSomething() {
fatalError("You must override me")
}
}
Now your base class confirms the protocol thanks to default implementation. But it will throw a fatal error at runtime:
class MyClass: MyProtocol {
// conformant
}
Child class, however, will run correctly as long as it overrides this function:
class MyOtherClass: MyClass {
func doSomething() {
print("Doing it!")
}
}
You could also move fatal error into base class, and not do any extension implementation.
In case of many instances of the same Class, that solution makes no sense. You can use a very simple callback design:
typealias MyDelegate = () -> Void
class MyClass {
var delegate: MyDelegate?
func doSomething() {
delegate?()
}
}
let x = MyClass()
x.delegate = {
print("do it!")
}
x.doSomething()
// Or you can use a defined function
func doIt() {
print("also doing it")
}
x.delegate = doIt
x.doSomething()
It can also be that you re looking for Strategy pattern, or Template pattern. Depends on your usage details.
Do I provide each object with its own closure during initialization, and then call that closure in the doSomething() method
Yes. That is extremely common and eminently Swifty. Incredibly miminalistic example:
struct S {
let f:()->()
func doYourThing() { f() }
}
let s = S { print("hello") }
let s2 = S { print("goodbye" )}
s.doYourThing() // hello
s2.doYourThing() // goodbye
Giving an object a settable method instance property is very, very easy and common. It doesn't have to be provided during initialization — you might set this property later on, and a lot of built-in objects work that way too.
That, after all, is all you're doing when you create a data task with dataTask(with:completionHandler:). You are creating a data task and handing it a function which it stores, and which it will call when it has performed the actual networking.
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
I've become a fan of using XCTestExpectation for this kind of thing. Here's an option.
class MyTestableClass: MyClass {
var methodAHandler: (() -> Void)?
// ...
override func methodA() {
methodAHandler?()
super.methodA()
}
And then in your test case
let expA = XCTestExpectation(description: "Method A Called")
let expB = ...
let expo = ...
objectUnderTest.methodAHandler = { expA.fulfill() }
/// ...
objectUnderTest.myMethod()
// ensure you use the enforceOrder param, which is optional
wait(for: [expA, expB, expC], timeout: 1.0, enforceOrder: true)
XCTestExpectation is made more for async testing, so the wait is slightly funny. But, it does do what you need, and would keep working even if eventually the internals of myMethod become asynchronous for some reason.
While I haven't used it myself, you also might want to check out Cuckoo. It's a mocking framework for Swift.
You're not asking the right question here. From a unit testing point of view you should not know/care that the tested method calls other methods, or even if other methods exist.
Unit tests should validate some observable result of the tested method. Anything that happens inside the tested method is irrelevant in the context of a unit test.
That's because unit tests should validate that the unit behaves as expected, i.e. they should validate against the specifications, not against the implementation.
Let's consider a simple example, unit testing a isPrime(n) function. Unless you're doing performance testing, you only care if the function returns the appropriate result for a couple of numbers. You don't care if the function checks all possible divisors, or if it uses a database of all known prime numbers, or if delegates the prime check to some 3rd party library/service.
The situation is not much different from yours. The fact that the three methods are called in a certain order needs to be validate via the external interface of the tested unit. For example if the three methods make API calls, then mock the API client and expect it to be requested three times, and with the expected URL/payload. If calling the three methods don't result in any noticeable changes, then there's not much you can test from the start, so again the fact that three methods are called in a certain order become irrelevant.
Unit testing is about validating the result of the execution of that unit, not anything more. Now, in an imperative programming language, the input->output functions are a minority, however this doesn't mean that we can't indirectly test if the function behaves as expected. You can use mocks, or validate some properties of the object after the function executes. Again, if there are no ways of externally checking the order of methods, then you have no specs to validate against.
I have recently read about how to add "Traits/Mixins" to a struct/class in Swift by creating a protocol and extending that protocol with a default implementation. This is great as it allows me to add functionality to view the controller without having to add a bunch of helper objects to said view controller. My question is, how do I stub calls that are provided by these default implementations?
Here is a simple example:
protocol CodeCop {
func shouldAllowExecution() -> Bool
}
extension CodeCop {
func shouldAllowExecution() -> Bool {
return arc4random_uniform(2) == 0
}
}
struct Worker : CodeCop {
func doSomeStuff() -> String {
if shouldAllowExecution() {
return "Cop allowed it"
} else {
return "Cop said no"
}
}
}
If I wanted to write two tests, one that verifies that the String "Cop allowed it" is returned by doStuff() when CodeCop does not allow execution, and another test that verifies that the String "Cop said no" is returned by doStuff() when CodeCop does not allow execution.
This is simple enough to do by writing an additional protocol in your test target, called CodeCopStub, that inherits from CodeCop:
protocol CodeCopStub: CodeCop {
// CodeCopStub declares a static value on the implementing type
// that you can use to control what is returned by
// `shouldAllowExecution()`.
//
// Note that this has to be static, because you can't add stored instance
// variables in extensions.
static var allowed: Bool { get }
}
Then extend CodeCopStub's shouldAllowExecution() method, inherited from CodeCop, to return a value depending on that new static variable allowed. This overrides the original CodeCop implementation for any type that implements CodeCopStub.
extension CodeCopStub {
func shouldAllowExecution() -> Bool {
// We use `Self` here to refer to the implementing type (`Worker` in
// this case).
return Self.allowed
}
}
All you have left to do at this point is to make Worker conform to CodeCopStub:
extension Worker: CodeCopStub {
// It doesn't matter what the initial value of this variable is, because
// you're going to set it in every test, but it has to have one because
// it's static.
static var allowed: Bool = false
}
Your tests will then look something like this:
func testAllowed() {
// Create the worker.
let worker = Worker()
// Because `Worker` has been extended to conform to `CodeCopStub`, it will
// have this static property. Set it to true to cause
// `shouldAllowExecution()` to return `true`.
Worker.allowed = true
// Call the method and get the result.
let actualResult = worker.doSomeStuff()
// Make sure the result was correct.
let expectedResult = "Cop allowed it"
XCTAssertEqual(expectedResult, actualResult)
}
func testNotAllowed() {
// Same stuff as last time...
let worker = Worker()
// ...but you tell it not to allow it.
Worker.allowed = false
let actualResult = worker.doSomeStuff()
// This time, the expected result is different.
let expectedResult = "Cop said no"
XCTAssertEqual(expectedResult, actualResult)
}
Remember that all of this code should go in your test target, not your main target. By putting it in your test target, none of it will affect your original code, and no modification to the original is required.
I am not sure if that is what you are looking for, but one way you can test this behavior without updating your code is by updating your project structure the following way:
Keep the CodeCop protocol in one file (let's say CodeCop.swift) and add the extension code into another one (CodeCop+shouldAllowExecution.swift)
While CodeCop.swift is linked to both your main target and your test target, CodeCop+shouldAllowExecution.swift is only in the main target.
Create a test file CodeCopTest.swift, only available in the test target, who contains another default implementation of shouldAllowExecution that will help you run your test.
Here's a potential CodeCopTest.swift file
import XCTest
fileprivate var shouldCopAllowExecution: Bool = false
fileprivate extension CodeCop {
func shouldAllowExecution() -> Bool {
return shouldCopAllowExecution
}
}
class PeopleListDataProviderTests: XCTestCase {
var codeCop: CodeCop!
override func setUp() {
super.setUp()
codeCop = CodeCop()
}
override func tearDown() {
codeCop = nil
super.tearDown()
}
func testWhenCopAllows() {
shouldCopAllowExecution = true
XCTAssertEqual(codeCop.doSomeStuff(), "Cop allowed it", "Cop should say 'Cop allowed it' when he allows execution")
}
func testWhenCopDenies() {
shouldCopAllowExecution = false
XCTAssertEqual(codeCop.doSomeStuff(), "Cop said no", "Cop should say 'Cop said no' when he does not allow execution")
}
}
I have code that follows the general design of:
protocol DispatchType {}
class DispatchType1: DispatchType {}
class DispatchType2: DispatchType {}
func doBar<D:DispatchType>(value:D) {
print("general function called")
}
func doBar(value:DispatchType1) {
print("DispatchType1 called")
}
func doBar(value:DispatchType2) {
print("DispatchType2 called")
}
where in reality DispatchType is actually a backend storage. The doBarfunctions are optimized methods that depend on the correct storage type. Everything works fine if I do:
let d1 = DispatchType1()
let d2 = DispatchType2()
doBar(value: d1) // "DispatchType1 called"
doBar(value: d2) // "DispatchType2 called"
However, if I make a function that calls doBar:
func test<D:DispatchType>(value:D) {
doBar(value: value)
}
and I try a similar calling pattern, I get:
test(value: d1) // "general function called"
test(value: d2) // "general function called"
This seems like something that Swift should be able to handle since it should be able to determine at compile time the type constraints. Just as a quick test, I also tried writing doBar as:
func doBar<D:DispatchType>(value:D) where D:DispatchType1 {
print("DispatchType1 called")
}
func doBar<D:DispatchType>(value:D) where D:DispatchType2 {
print("DispatchType2 called")
}
but get the same results.
Any ideas if this is correct Swift behavior, and if so, a good way to get around this behavior?
Edit 1: Example of why I was trying to avoid using protocols. Suppose I have the code (greatly simplified from my actual code):
protocol Storage {
// ...
}
class Tensor<S:Storage> {
// ...
}
For the Tensor class I have a base set of operations that can be performed on the Tensors. However, the operations themselves will change their behavior based on the storage. Currently I accomplish this with:
func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S> { ... }
While I can put these in the Tensor class and use extensions:
extension Tensor where S:CBlasStorage {
func dot(_ tensor:Tensor<S>) -> Tensor<S> {
// ...
}
}
this has a few side effects which I don't like:
I think dot(lhs, rhs) is preferable to lhs.dot(rhs). Convenience functions can be written to get around this, but that will create a huge explosion of code.
This will cause the Tensor class to become monolithic. I really prefer having it contain the minimal amount of code necessary and expand its functionality by auxiliary functions.
Related to (2), this means that anyone who wants to add new functionality will have to touch the base class, which I consider bad design.
Edit 2: One alternative is that things work expected if you use constraints for everything:
func test<D:DispatchType>(value:D) where D:DispatchType1 {
doBar(value: value)
}
func test<D:DispatchType>(value:D) where D:DispatchType2 {
doBar(value: value)
}
will cause the correct doBar to be called. This also isn't ideal, as it will cause a lot of extra code to be written, but at least lets me keep my current design.
Edit 3: I came across documentation showing the use of static keyword with generics. This helps at least with point (1):
class Tensor<S:Storage> {
// ...
static func cos(_ tensor:Tensor<S>) -> Tensor<S> {
// ...
}
}
allows you to write:
let result = Tensor.cos(value)
and it supports operator overloading:
let result = value1 + value2
it does have the added verbosity of required Tensor. This can made a little better with:
typealias T<S:Storage> = Tensor<S>
This is indeed correct behaviour as overload resolution takes place at compile time (it would be a pretty expensive operation to take place at runtime). Therefore from within test(value:), the only thing the compiler knows about value is that it's of some type that conforms to DispatchType – thus the only overload it can dispatch to is func doBar<D : DispatchType>(value: D).
Things would be different if generic functions were always specialised by the compiler, because then a specialised implementation of test(value:) would know the concrete type of value and thus be able to pick the appropriate overload. However, specialisation of generic functions is currently only an optimisation (as without inlining, it can add significant bloat to your code), so this doesn't change the observed behaviour.
One solution in order to allow for polymorphism is to leverage the protocol witness table (see this great WWDC talk on them) by adding doBar() as a protocol requirement, and implementing the specialised implementations of it in the respective classes that conform to the protocol, with the general implementation being a part of the protocol extension.
This will allow for the dynamic dispatch of doBar(), thus allowing it to be called from test(value:) and having the correct implementation called.
protocol DispatchType {
func doBar()
}
extension DispatchType {
func doBar() {
print("general function called")
}
}
class DispatchType1: DispatchType {
func doBar() {
print("DispatchType1 called")
}
}
class DispatchType2: DispatchType {
func doBar() {
print("DispatchType2 called")
}
}
func test<D : DispatchType>(value: D) {
value.doBar()
}
let d1 = DispatchType1()
let d2 = DispatchType2()
test(value: d1) // "DispatchType1 called"
test(value: d2) // "DispatchType2 called"
How can we determine if protocol conforms to a specific subtype based on user provided instances, if it's not possible this way, any alternate solutions.
API
protocol Super {}
protocol Sub: Super {} //inherited by Super protocol
class Type1: Super {} //conforms to super protocol
class Type2: Type1, Sub {} //conforms to sub protocol
inside another API class
func store(closures: [() -> Super]) {
self.closures = closures
}
when it's time to call
func go() {
for closure in closures {
var instance = closure()
if instance is Super {
//do something - system will behave differently
} else { //it's Sub
//do something else - system will behave differently
}
}
}
users of the api
class Imp1: Type1 {}
class Imp2: Type2 {}
var closures: [() -> Super] = [ { Imp1() }, { Imp2() } ]
store(closures)
my current workaround within API
func go() {
for closure in closures {
var instance = closure()
var behavior = 0
if instance as? Type2 != nil { //not so cool, should be through protocols
behavior = 1 //instead of implementations
}
if behavior == 0 { //do something within the api,
} else { //do something else within the api
}
//instance overriden method will be called
//but not important here to show, polymorphism works in here
//more concerned how the api can do something different based on the types
}
}
You are jumping through a lot of hoops to manually recreate dynamic dispatch, i.e. one of the purposes of protocols and classes. Try actually using real runtime polymorphism to solve your problem.
Take this code:
if instance is Super {
//do something
} else { //it's Sub
//do something else
}
What you are saying is, if it’s a superclass, run the superclass method, else, run the subclass. This is a bit inverted – normally when you are a subclass you want to run the subclass code not the other way around. But assuming you turn it around to the more conventional order, you are essentially describing calling a protocol’s method and expecting the appropriate implementation to get called:
(the closures aren’t really related to the question in hand so ignoring them for now)
protocol Super { func doThing() }
protocol Sub: Super { } // super is actually a bit redundant here
class Type1: Super {
func doThing() {
println("I did a super thing!")
}
}
class Type2: Sub {
func doThing() {
println("I did a sub thing!")
}
}
func doSomething(s: Super) {
s.doThing()
}
let c: [Super] = [Type1(), Type2()]
for t in c {
doSomething(t)
}
// prints “I did a super thing!”, then “I did a sub thing!"
Alternatives to consider: eliminate Sub, and have Type2 inherit from Type1. Or, since there’s no class inheritance here, you could use structs rather than classes.
Almost any time you find yourself wanting to use is?, you probably meant to use an enum. Enums allow you use to the equivalent of is? without feeling bad about it (because it isn't a problem). The reason that is? is bad OO design is that it creates a function that is closed to subtyping, while OOP itself is always open to subtyping (you should think of final as a compiler optimization, not as a fundamental part of types).
Being closed to subtyping is not a problem or a bad thing. It just requires thinking in a functional paradigm rather than an object paradigm. Enums (which are the Swift implementation of a Sum type) are exactly the tool for this, and are very often a better tool than subclassing.
enum Thing {
case Type1(... some data object(s) ...)
case Type2(... some data object(s) ...)
}
Now in go(), instead of an is? check, you switch. Not only is this not a bad thing, it's required and fully type-checked by the compiler.
(Example removes the lazy closures since they're not really part of the question.)
func go(instances: [Thing]) {
for instance in instances {
switch instance {
case Type1(let ...) { ...Type1 behaviors... }
case Type2(let ...) { ...Type2 behaviors... }
}
}
}
If you have some shared behaviors, just pull those out into a function. You're free to let your "data objects" implement certain protocols or be of specific classes if that makes things easier to pass along to shared functions. It's fine if Type2 takes associated data that happens to be a subclass of Type1.
If you come along later and add a Type3, then the compiler will warn you about every switch that fails to consider this. That's why enums are safe while is? is not.
You need objects derived from the Objective-C world to do this:
#objc protocol Super {}
#objc protocol Sub: Super {}
class Parent: NSObject, Super {}
class Child: NSObject, Sub {}
func go( closures: [() -> Super]) {
for closure in closures {
let instance = closure()
if instance is Sub { // check for Sub first, check for Super is always true
//do something
} else {
//do something else
}
}
}
Edit: Version with different method implementations:
protocol Super {
func doSomething()
}
protocol Sub: Super {}
class Parent: Super {
func doSomething() {
// do something
}
}
class Child: Sub {
func doSomething() {
// do something else
}
}
func go( closures: [() -> Super]) {
for closure in closures {
let instance = closure()
instance.doSomething()
}
}