Ho una classe che voglio mettere alla prova con XCTest, e questa classe simile a questa:Mocking Singleton/sharedInstance a Swift
public class MyClass: NSObject {
func method() {
// Do something...
// ...
SingletonClass.sharedInstance.callMethod()
}
}
La classe utilizza un Singleton che viene implementato come questo:
public class SingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = SingletonClass()
private override init() {
super.init()
}
func callMethod() {
// Do something crazy that shouldn't run under tests
}
}
Ora per il test. Voglio testare che method()
fa effettivamente quello che dovrebbe fare, ma non voglio richiamare il codice in callMethod()
(perché fa cose orribili asincrone/rete/thread che non dovrebbero essere eseguite sotto test di MyClass, e farà crash i test).
Quindi quello che fondamentalmente vorrei fare è questo:
SingletonClass = MockSingletonClass: SingletonClass {
override func callMethod() {
// Do nothing
}
let myObject = MyClass()
myObject.method()
// Check if tests passed
Questo ovviamente non è valido Swift, ma si ottiene l'idea. Come posso ignorare lo callMethod()
solo per questo particolare test, per renderlo innocuo?
MODIFICA: Ho provato a risolverlo utilizzando una forma di dipendenza, ma ho riscontrato grossi problemi. Ho creato un init-metodo personalizzato solo per essere utilizzato per le prove in modo che avrei potuto creare i miei oggetti come questo:
let myObject = MyClass(singleton: MockSingletonClass)
e lasciare MyClass simile a questa
public class MyClass: NSObject {
let singleton: SingletonClass
init(mockSingleton: SingletonClass){
self.singleton = mockSingleton
}
init() {
singleton = SingletonClass.sharedInstance
}
func method() {
// Do something...
// ...
singleton.callMethod()
}
}
miscelazione in codice di test con il resto del codice è qualcosa che trovo un po 'spiacevole, ma va bene. Il grosso problema era che avevo due singletons costruite come questo nel mio progetto, sia riferimento a vicenda:
public class FirstSingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = FirstSingletonClass()
let secondSingleton: SecondSingletonClass
init(mockSingleton: SecondSingletonClass){
self.secondSingleton = mockSingleton
}
private override init() {
secondSingleton = SecondSingletonClass.sharedInstance
super.init()
}
func someMethod(){
// Use secondSingleton
}
}
public class SecondSingletonClass: NSObject {
// Only accessible using singleton
static let sharedInstance = SecondSingletonClass()
let firstSingleton: FirstSingletonClass
init(mockSingleton: FirstSingletonClass){
self.firstSingleton = mockSingleton
}
private override init() {
firstSingleton = FirstSingletonClass.sharedInstance
super.init()
}
func someOtherMethod(){
// Use firstSingleton
}
}
Questo ha creato una situazione di stallo in cui uno dei single in cui utilizzate prima, come il metodo init avrebbe aspettato per l'init metodo dell'altro, e così via ...
Soluzione orribile per lasciare che le prove perdano nel codice di produzione – IlyaEremin