Быстрые одиночные тесты

Я пытаюсь научиться тестировать с 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))
            }
        }
    }
}
}

Как я могу проверить, что мой синглтон является потокобезопасным?

1 ответ

Чтобы проверить, что ваш синглтон безопасен для потоков, я сделал небольшой пример. Вы можете найти весь код в этом репозитории Github в основном:

  1. создавая кучу потоков, просящих синглтон
  2. хранение каждого возвращаемого объекта в массиве
  3. проверка всех объектов, содержащихся в этом массиве, одинаковы

Я обнаружил несколько проблем (используя Xcode 6.2 ergo Swift 1.1), даже сбои компилятора. Итак, после этого принятого SO ответа я изменил вашу реализацию Singleton, избегая классического использования GCD. Этими указателями и небезопасными изменяемыми указателями вы должны управлять, и из-за этого у меня возникали сбои

Итак, ваш синглтон-класс сейчас:

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)

Здесь я просто вызываю функцию, чтобы убедиться, что каждый сохраненный объект совпадает с переданным синглтоном, и даю 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)

                }
            }

        }


            }
}
Другие вопросы по тегам