Sono principalmente interessato alle risposte in merito a una lingua Swift, ma le risposte più generali sono sempre ben accette.
Voglio testare una classe (CUT), e per questo userò l'iniezione di dipendenza. Ora, posso:
- Crea un protocollo che verrà utilizzato dal mio CUT, a cui saranno conformi alcune classi concrete e alcune classi di stub.
- Basta usare la classe concreta nel mio CUT e avere una classe stub come sottoclasse della classe concreta. La classe Stub sostituirà solo i metodi che CUT sta utilizzando dalla classe concreta.
Esempio per l'opzione 1:
// PRODUCTION CODE
class A {
func incrementedValueOf(_ b: BProtocol) -> Int {
return b.value + 1
}
}
protocol BProtocol {
func value() -> Int
}
class B: BProtocol {
func value() -> Int { return calculateValueSomehow() }
func calculateValueSomehow() -> Int { return ... }
}
// TEST CODE
class BStub: BProtocol {
var valueToProvide: Int = 0
func value() -> Int { return valueToProvide }
}
class ATests: XCTestCase {
func testIncrementedValueOf() {
let bStub = BStub()
bStub.valueToProvide = 11
let a = A()
XCTAssertEqual(a.incrementedValueOf(bStub), bStub.valueToProvide + 1)
}
}
Esempio per l'opzione 2:
// PRODUCTION CODE
class A {
func incrementedValueOf(_ b: B) -> Int {
return b.value + 1
}
}
// Note: BProtocol is removed
class B {
func value() -> Int { return calculateValueSomehow() }
func calculateValueSomehow() -> Int { return ... }
}
// TEST CODE
class BStub: B {
var valueToProvide: Int = 0
override func value() -> Int { return valueToProvide }
// Note: calculateValueSomehow is not overridden
}
class ATests: XCTestCase {
func testIncrementedValueOf() {
let bStub = BStub()
bStub.valueToProvide = 11
let a = A()
XCTAssertEqual(a.incrementedValueOf(bStub), bStub.valueToProvide + 1)
}
}
C'è un lato negativo nell'usare l'opzione 2?
-
A
eB
sono più strettamente accoppiati? - C'è qualche problema se la classe
B
è una parte di un diverso framework? Forse sarà un problema in futuro Swift seA
utilizza un metodo daB
che èpublic
ma nonopen
, quindi non sarà sovrascrivibile (ad esempiovalue()
)?