2016-06-22 9 views
1

Я получил этот класс, который я хотел бы писать тесты для:тесты писать юнит для RxSwift

import CoreLocation 
import RxCocoa 
import RxSwift 

struct LocationManager { 

    private (set) var authorized: Driver<Bool> 
    private let coreLocationManager = CLLocationManager() 

    init() { 
     coreLocationManager.distanceFilter = kCLDistanceFilterNone 
     coreLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation 

     authorized = Observable.deferred { [weak coreLocationManager] in 
      let status = CLLocationManager.authorizationStatus() 
      guard let coreLocManager = coreLocationManager else { 
       return Observable.just(status) 
      } 
      return coreLocManager 
       .rx_didChangeAuthorizationStatus 
       .startWith(status) 
      } 
      .asDriver(onErrorJustReturn: CLAuthorizationStatus.NotDetermined) 
      .map { 
       switch $0 { 
       case .AuthorizedWhenInUse: 
        return true 
       default: 
        return false 
       } 
     } 

     coreLocationManager.requestWhenInUseAuthorization() 
    } 
} 

В основном я хочу, чтобы проверить, имеет ли уполномоченный Driver правильное значение, основанное на возможных CLAuthorizationStatuses. Мне нужен намек в правильном направлении, так как я не знаком с модульным тестированием с RxSwift. Я думаю, что мой лучший вариант - создать макет CLLocationManager, который возвращает некоторый CLAuthorizationStatus, когда вызывается authorizationStatus(), и после этого я проверю значение авторизованного Driver правильно?

Любое объяснение того, как протестировать этот класс LocationManager, оценено.

ответ

2

OK Я получил его работу. Однако я не уверен, что это допустимое решение. Не стесняйтесь исправить меня здесь.

Прежде всего я изменил мой класс LocationManager к этому:

import CoreLocation 
import RxCocoa 
import RxSwift 

struct LocationManager<T where T: LocationManagerProtocol> { 

    private (set) var authorized: Driver<Bool> 
    private let coreLocationManager = CLLocationManager() 

    init(type: T.Type) { 
     coreLocationManager.distanceFilter = kCLDistanceFilterNone 
     coreLocationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation 

     authorized = Observable.deferred { [weak coreLocationManager] in 
      let status = type.authorizationStatus() 
      guard let coreLocManager = coreLocationManager else { 
       return Observable.just(status) 
      } 
      return coreLocManager 
       .rx_didChangeAuthorizationStatus 
       .startWith(status) 
      } 
      .asDriver(onErrorJustReturn: CLAuthorizationStatus.NotDetermined) 
      .map { 
       switch $0 { 
       case .AuthorizedWhenInUse: 
        return true 
       default: 
        return false 
       } 
     } 

     coreLocationManager.requestWhenInUseAuthorization() 
    } 
} 

В принципе можно теперь представить тип, соответствующий новый протокол я написал LocationManagerProtocol.

Далее протокол реализует функцию authorizationStatus, поэтому я могу издеваться над этим.

protocol LocationManagerProtocol { 
    static func authorizationStatus() -> CLAuthorizationStatus 
} 

Затем я создал расширение для CLLocationManager для реализации этого протокола:

import CoreLocation 

extension CLLocationManager: LocationManagerProtocol { 

} 

вызов из кода продукции:let locationManager = LocationManager(type: CLLocationManager.self)

Зов тестового кода:let locationManager = LocationManager(type: AuthorizedLocationManager.self) или let locationManager = LocationManager(type: ForbiddenLocationManager.self)

В моем тестовом классе я добавил эти два класса два переопределить метод authorizationStatus:

class AuthorizedLocationManager: LocationManagerProtocol { 
    static func authorizationStatus() -> CLAuthorizationStatus { 
     return .AuthorizedWhenInUse 
    } 
} 

class ForbiddenLocationManager: LocationManagerProtocol { 
    static func authorizationStatus() -> CLAuthorizationStatus { 
     return .Denied 
    } 
} 

Мои тестовые примеры:

func testLocationAuthorizationPermitted() { 
    let locationManager = LocationManager(type: AuthorizedLocationManager.self) 

    locationManager.authorized 
    .driveNext { authorized in 
     XCTAssertTrue(authorized) 
    } 
    .addDisposableTo(disposeBag) 
} 

func testLocationAuthorizationRejected() { 
    let locationManager = LocationManager(type: ForbiddenLocationManager.self) 

    locationManager.authorized 
     .driveNext { authorized in 
      XCTAssertFalse(authorized) 
     } 
     .addDisposableTo(disposeBag) 
} 

Извините за длинный пост. Я думал, что дам вам всю информацию о том, как я решил это сейчас. Однако, как я уже говорил ранее, я новичок в этом и хотел бы услышать другие мнения по этому подходу и является ли это допустимым тестовым сценарием или нет.

Смежные вопросы