我得到了这门课,我想为其编写测试:
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
的模拟,它会在调用authorizationStatus()
时返回一些CLAuthorizationStatus,之后我会检查授权Driver
权限的值吗?
对于如何测试此LocationManager
课程的任何解释表示赞赏。
答案 0 :(得分:2)
好的,我搞定了。但是我不确定这是否是一个有效的解决方案。请随意在这里纠正我。
首先,我将我的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)
}
对不起,很长的帖子。我想我会告诉你关于我现在如何解决这个问题的所有信息。然而,正如我之前所说,我是新手,并希望听到关于这种方法的其他意见,以及这是否是一个有效的测试场景。
答案 1 :(得分:1)
看看RxSwift
如何实现单元测试:https://github.com/ReactiveX/RxSwift/blob/4b3056b81f619c0bf12c6ee4e571582219e2b88d/Tests/RxSwiftTests/Tests/Observable%2BSingleTest.swift
至于使用CLLocationManager
的模拟,是的,依赖注入将是最佳选择。