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 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 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])
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"
I'm trying to test a class but I'm kind of confused as to what to test. Here is the class I want to unit test:
class CalculatorBrain {
private var accumulator = 0.0
func setOperand(operand: Double) {
accumulator = operand
}
var result: Double {
return accumulator
}
private var operations: Dictionary<String, Operation> = [
"=" : .Equals,
"π" : .Constant(M_PI),
"e" : .Constant(M_E),
"±" : .UnaryOperation({ (op1: Double) -> Double in return -op1 }),
"√" : .UnaryOperation(sqrt ),
"cos": .UnaryOperation(cos),
"+" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 + op2 }),
"−" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 - op2 }),
"×" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 * op2 }),
"÷" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 / op2 })
]
private enum Operation {
case Constant(Double)
case UnaryOperation((Double) -> Double)
case BinaryOperation((Double, Double) -> Double)
case Equals
}
func performOperation(symbol: String) {
if let operation = operations[symbol] {
switch operation {
case .Constant(let value):
accumulator = value
case .UnaryOperation(let function):
accumulator = function(accumulator)
case .BinaryOperation(let function):
executePendingBinaryOperation()
pendingBinaryOperation = PendingBinaryOperationInfo(binaryOperation: function, firstOperand: accumulator)
case .Equals:
executePendingBinaryOperation()
}
}
}
private var pendingBinaryOperation: PendingBinaryOperationInfo?
private struct PendingBinaryOperationInfo {
var binaryOperation: (Double, Double) -> Double
var firstOperand: Double
}
private func executePendingBinaryOperation() {
if let pending = pendingBinaryOperation {
accumulator = pending.binaryOperation(pending.firstOperand, accumulator)
pendingBinaryOperation = nil
}
}
}
For the code above, what would be good tests.
Is it worth testing every single operation (+, -, *, /, etc) in the dictionary operations?
Is it worth testing the private methods?
You can't test private methods in Swift using #testable. You can only test methods marked either internal or public. As the docs say:
Note: #testable provides access only for “internal” functions;
“private” declarations are not visible outside of their file even when
using #testable.
Read more here
Unit testing should be considered black box testing, which means you don't care about the internals of the unit you test. You are mainly interested to see what's the unit output based on the inputs you give it in the unit test.
Now, by outputs we can assert on several things:
the result of a method
the state of the object after acting on it,
the interaction with the dependencies the object has
In all cases, we are interested only about the public interface, since that's the one that communicates with the rest of the world.
Private stuff don't need to have unit tests simply because any private item is indirectly used by a public one. The trick is to write enough tests that exercise the public members so that the private ones are fully covered.
Also, one important thing to keep in mind is that unit testing should validate the unit specifications, and not its implementation. Validating implementation details adds a tight coupling between the unit testing code and the tested code, which has a big disadvantage: if the tested implementation detail changes, then it's likely that the unit test will need to be changed also.
Writing unit tests in a black box manner means that you'll be able to refactor all the code in those units without worrying that by also having to change the tests you risk into introducing bugs in the unit testing code. Unreliable unit tests are sometimes worse than a lack of tests, as tests that give false positives are likely to hide actual bugs in your code.
Although I agree with not testing private stuff, and I'd rather prefer to test just public interface, sometimes I've needed to test something inside a class that was hidden (like a complex state machine). For these cases what you can do is:
import Foundation
public class Test {
internal func testInternal() -> Int {
return 1
}
public func testPublic() -> Int {
return 2
}
// we can't test this!
private func testPrivate() -> Int {
return 3
}
}
// won't ship with production code thanks to #if DEBUG
// add a good comment with "WHY this is needed 😉"
#if DEBUG
extension Test {
public func exposePrivate() -> Int {
return self.testPrivate()
}
}
#endif
Then you can do this:
import XCTest
#testable import TestTests
class TestTestsTests: XCTestCase {
func testExample() {
let sut = Test()
XCTAssertEqual(1, sut.testInternal())
}
func testPrivateExample() {
let sut = Test()
XCTAssertEqual(3, sut.exposePrivate())
}
}
I understand perfectly that this is a hack. But knowing this trick can save your bacon in the future or not. Do not abuse this trick.
Diego's answer is clever but it is possible to go further.
Go into your project editor and define a new Testing Configuration by duplicating the Debug configuration.
Edit your scheme's Test action so that the build configuration is Testing.
Now edit your test target's build settings to define an additional Active Compilation Conditions value for the Testing configuration, "TESTING".
Now you can say #if TESTING, as distinct from mere DEBUG.
I use this, for example, to declare initializers that only a test can see.
Short answer is you can't. Private parts can't be tested.
However, I don't think "you shouldn't" is a valid answer. I used to think in this way, but real life scenarios are more complicated than we would expect. At some point, I need to write a FileScanner class as part of a framework, which conforms to a Scanner protocol that only has a scan(filename: String) function. Of course FileScanner.scan(filename: String) needs to be public, but how about the functions that support scan?
As I mentioned in a comment above, I want to:
keep the interface as clean as possible, and
limit access level as private as possible
Which means I don't want to expose other functions that are not used by other classes. I really hope there's a #testable modifier at function level (works like #discardable etc) but since it's not really there in Swift, we unfortunately only have 2 options:
Write unit tests for scan only, which is suggested by most people. This requires a lot of input files in the unit test bundle (not necessarily Target, as I'm using SPM only without Xcode, and it's just a Tests directory), and is hard to create specific cases for individual functions. Depends on how complex scan is, it's not really a good approach.
Expose private other functions. I ended up with this approach, and make a convention, that if a function doesn't have any modifier, we assume it's internal and can be used by other files in the same bundle (Target), just not public. But if we specifically mark it as internal func etc, it means we just want to make it #testable and it should never be used by other classes in the same bundle.
So, my conclusion is that even you can't test private methods and properties in Swift yet, I consider it as a limitation of Swift but not an invalid use case.
I found this link which is saying something similar with Cristik.
Basically, you are asking the wrong question, you should not be seeking to test the class/functions marked with "private".
I think actually don’t need to test of private members.
But if you want to use to private members(properties & methods) at UnitTest, there is a way that use Protocol.
Protocol PrivateTestable {
associatedtype PrivateTestCase
var privateTestCase: PrivateTestCase {get}
}
And try to extension the protocol in same file (target class file).
extension CalculatorBrain: PrivateTestable {
struct PrivateTestCase {
private let target: CalculatorBrain
var pendingBinaryOperation: PendingBinaryOperationInfo? {
return target.pendingBinaryOperation
}
init(target: CalculatorBrain) {
self.target = target
}
}
var privateTestable: PrivateTestCase {
return PrivateTestCase(target: self)
}
}
Then you can use pendingBinaryOperation in UnitTest
class CalculatorBrainTest: XCTestCase {
func testPendingBinaryOperation() {
let brain = CalculatorBrain()
XCTAssertNotNil(brain.privateTestCase.pendingBinaryOperation)
}
}
If you really want to get a private field in tests, you can use the Mirror class:
let testClass = CalculatorBrain()
let mirror = Mirror(reflecting: testClass)
func extract<T>(variable name: StaticString, mirror: Mirror?) -> T? {
guard let mirror = mirror else {
return nil
}
guard let descendant = mirror.descendant("\(name)") as? T
else {
return extract(variable: name, mirror: mirror)
}
return descendant
}
let result: Dictionary<String, Any>? = extract(variable: "operations", mirror: mirror)
print(result!)
For example, I made an extension of the class to check the output result
extension CalculatorBrain {
var test: Any {
operations
}
}
print("")
print(testClass.test)
As a result, I got this:
Mirror
["−": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function)),
"√": __lldb_expr_24.CalculatorBrain.Operation.UnaryOperation((Function)),
"+": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function)),
"÷": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function)),
"e": __lldb_expr_24.CalculatorBrain.Operation.Constant(2.718281828459045),
"π": __lldb_expr_24.CalculatorBrain.Operation.Constant(3.141592653589793),
"cos": __lldb_expr_24.CalculatorBrain.Operation.UnaryOperation((Function)),
"=": __lldb_expr_24.CalculatorBrain.Operation.Equals,
"±": __lldb_expr_24.CalculatorBrain.Operation.UnaryOperation((Function)),
"×": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function))]
Extension
["×": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function)),
"÷": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function)),
"√": __lldb_expr_24.CalculatorBrain.Operation.UnaryOperation((Function)),
"=": __lldb_expr_24.CalculatorBrain.Operation.Equals,
"−": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function)),
"±": __lldb_expr_24.CalculatorBrain.Operation.UnaryOperation((Function)),
"e": __lldb_expr_24.CalculatorBrain.Operation.Constant(2.718281828459045),
"cos": __lldb_expr_24.CalculatorBrain.Operation.UnaryOperation((Function)),
"π": __lldb_expr_24.CalculatorBrain.Operation.Constant(3.141592653589793),
"+": __lldb_expr_24.CalculatorBrain.Operation.BinaryOperation((Function))]
Private methods will not be tested (at least I do not know how to do this without changing the main code)