Swift单例测试

时间:2014-10-10 09:24:45

标签: ios swift testing tdd quick-nimble

我正在尝试使用Quick和Nimble学习测试,我编写了简单的单例和一些测试

的Singleton:

public class LocationManager : NSObject {
// Singleton
public class var sharedInstance : LocationManager {
    struct Static {
        static var instance : LocationManager?
        static var token : dispatch_once_t = 0
        }
    dispatch_once(&Static.token) {
        Static.instance = LocationManager()
    }
    return Static.instance!
    }
}

我的测试:

class LocationManagerSpec: QuickSpec {
override func spec() {
    describe("Location manager") {

        let locationManager = LocationManager.sharedInstance

        context("initialized") {
            it("is not nil") {
                expect(locationManager).notTo(beNil())
            }
            it("is unique") {
                let tempLocationManager = LocationManager()
                expect(locationManager).notTo(equal(tempLocationManager))
            }
            it("and shared instances are same") {
                let tempLocationManager = LocationManager.sharedInstance
                expect(locationManager).to(equal(tempLocationManager))
            }
        }
    }
}
}

如何测试我的单例是否是线程安全的?

1 个答案:

答案 0 :(得分:0)

为了测试你的Singleton是线程安全的我做了一点样本。您可以在Github repo基本上找到所有代码:

  1. 创建一堆线程,要求单身人士
  2. 将每个返回的对象存储在数组
  3. 检查该数组中包含的所有对象是否相同
  4. 我发现了几个问题(使用Xcode 6.2 ergo Swift 1.1),甚至编译器崩溃。因此,在this accepted SO answer之后,我改变了您的Singleton实现,避免了GCD的经典使用。你需要管理这些指针和不安全的可变指针,我因此而崩溃了

    所以你的Singleton课程现在是:

    import Foundation
    
    
    public class LocationManager: NSObject {
    
        public class var sharedInstance: LocationManager {
            struct Static {
                static let instance: LocationManager = LocationManager()
            }
            return Static.instance
        }
    
    }
    

    要测试它,你需要等到所有线程都完成。当测试运行器在MainThread上运行时,您需要使用期望

     describe("Accesing Location manager from multiple concurrent threads") {
                context("When created") {
                    it("should return always the same object for every of these 500 threads") {
                        var allSingletons = Array<LocationManager>()
    
                        for i in 1...10 {
                            println("Launching thread \(i)")
    
                            dispatch_async(self.globalBackgroundQueue) {
                                allSingletons.append(LocationManager.sharedInstance)
                            }
                        }
    
                        expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
    
                    }
                }
    
            }
    

    重要的是这一部分:

    expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
    

    这里我只是调用一个函数来确定每个存储的对象是否与传递的Singleton相同,并给出10秒超时

    整个测试类:

    import Quick
    import Nimble
    import QuickNimbleExample
    
    
    
    
    class LocationManagerSpec: QuickSpec {
        var globalBackgroundQueue: dispatch_queue_t {
            return dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0)
        }
    
        func allSingletonsEqual(#inArray: Array<LocationManager>, singleton: LocationManager) -> Bool {
    
            for loc in inArray {
                if loc != singleton {
                    return false
                }
            }
    
            return true
        }
    
    
        override func spec() {
    
            describe("Accesing Location manager from multiple concurrent threads") {
                context("When created") {
                    it("should return always the same object for every of these 500 threads") {
                        var allSingletons = Array<LocationManager>()
    
                        for i in 1...10 {
                            println("Launching thread \(i)")
    
                            dispatch_async(self.globalBackgroundQueue) {
                                allSingletons.append(LocationManager.sharedInstance)
                            }
                        }
    
                        expect(self.allSingletonsEqual(inArray: allSingletons, singleton: LocationManager.sharedInstance)).toEventually(beTrue(), timeout: 10)
    
                    }
                }
    
            }
    
    
                }
    }