2

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

单身人士:

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

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

4

1 回答 1

0

为了测试你的单例是线程安全的,我做了一个小样本。您基本上可以在这个Github repo中找到所有代码:

  1. 创建一堆线程要求单例
  2. 将每个返回的对象存储在一个数组中
  3. 检查该数组中包含的所有对象是否相同

我发现了几个问题(使用 Xcode 6.2 ergo Swift 1.1),甚至编译器崩溃。因此,按照这个接受的 SO 答案,我已经更改了您的 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)

                }
            }

        }


            }
}
于 2015-03-21T12:34:53.400 回答