wenderlich unit test swift unit-testing

unit - Swift-Unidad de pruebas de variables privadas y métodos



wenderlich swift (4)

Estoy tratando de evaluar una clase pero estoy confundido en cuanto a qué probar. Aquí está la clase que quiero probar por unidad:

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 } } }

Para el código anterior, lo que serían buenas pruebas.

¿Vale la pena probar cada operación individual (+, -, *, /, etc.) en las operations diccionario?

¿Vale la pena probar los métodos privados?


Aunque estoy de acuerdo en no probar cosas private , y prefiero probar solo la interfaz pública, a veces he necesitado probar algo dentro de una clase que estaba oculta (como una máquina de estados compleja). Para estos casos lo que puedes hacer es:

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 } } // this extension should be in its own file // 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

Entonces puedes hacer esto:

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()) } }

Entiendo perfectamente que esto es un hack. Pero conocer este truco puede salvar tu tocino en el futuro o no. No abuses de este truco.


Encontré este enlace que dice algo similar con Cristik.

Básicamente, estás haciendo la pregunta incorrecta, no debes buscar probar la clase / funciones marcadas con "privado".


La prueba de unidad por definición es prueba de caja negra, lo que significa que no le importan los aspectos internos de la unidad que prueba. Lo que más le interesa es ver cuál es la salida de la unidad según las entradas que le da en la prueba de la unidad.

Ahora, por salidas podemos afirmar sobre varias cosas:

  • el resultado de un método
  • el estado del objeto después de actuar sobre él,
  • La interacción con las dependencias que tiene el objeto.

En todos los casos, solo nos interesa la interfaz pública, ya que es la que se comunica con el resto del mundo.

Las cosas privadas no necesitan tener pruebas unitarias simplemente porque cualquier elemento privado es usado indirectamente por uno público. El truco consiste en escribir suficientes pruebas que ejerciten a los miembros públicos para que los privados estén completamente cubiertos.

Además, una cosa importante a tener en cuenta es que las pruebas unitarias deben validar las especificaciones de la unidad y no su implementación. La validación de los detalles de la implementación agrega un acoplamiento estrecho entre el código de prueba de la unidad y el código probado, lo que tiene una gran desventaja: si los detalles de la implementación probada cambian, entonces es probable que la prueba de la unidad también deba cambiarse, y esto disminuye el beneficio. Prueba unitaria para esa pieza de código.


No puedes probar métodos privados en Swift usando @testable . Solo puedes probar métodos marcados ya sea internal o public . Como dicen los doctores:

Nota: @testable proporciona acceso solo para funciones "internas"; Las declaraciones "privadas" no son visibles fuera de su archivo, incluso cuando se usa @testable.

Lea más here