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?
Unit Tests Should Only Test Public Methods The short answer is that you shouldn't test private methods directly, but only their effects on the public methods that call them. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object.
You have to find the private headers, copy them to your project, create a bridging header file, and import the private headers. Or you can use message sending techniques to perform a method selector on a target object, and extract the returned value and convert it to a Swift type.
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:
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.
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