pol*_*ech 6 unit-testing mocking ios xctest swift
我正在尝试对简单的 HttpClient 行为进行单元测试。为此,我创建了一个 GenericHttpClientInterface 协议和实现该协议的具体类 GenericHttpClient。
protocol GenericHttpClientInterface {
func makeRequest<T: Decodable>(request: URLRequest) -> Observable<T>
}
class GenericHttpClient: GenericHttpClientInterface {
func makeRequest<T: Decodable>(request: URLRequest) -> Observable<T> {
return URLSession.shared.rx.data(request: request).jsonDecode(to: T.self)
}
}
Run Code Online (Sandbox Code Playgroud)
我想要实现的是模拟该类:
class MockHttpClient: GenericHttpClientInterface {
var invokedMakeRequestCount = 0
var invokedMakeRequestParameters: (request: URLRequest, Void)?
var stubbedMakeRequestResult: Observable<Any>!
func makeRequest<T: Decodable>(request: URLRequest) -> Observable<T> {
invokedMakeRequestCount += 1
invokedMakeRequestParameters = (request, ())
return stubbedMakeRequestResult as! Observable<T>;
}
}
Run Code Online (Sandbox Code Playgroud)
给ma带来的问题是,我正在模拟的方法具有通用参数T,其中是请求将被解码到的类。在我调用这个函数之前我不知道这个参数,所以基本上在 MockHttpClient 类中为我创建的 makeRequest 存储存根数据的属性:
stubbedMakeRequestResult: Observable<Any>
返回它后,我尝试将其转换为结果类型 Observable。这给了我一个警告
Cast from 'Observable<Any>?' to unrelated type 'Observable<T>' always fails
Run Code Online (Sandbox Code Playgroud)
结果
Thread 1: signal SIGABRT.
Run Code Online (Sandbox Code Playgroud)
知道如何存根该数据吗?
创建 SIGABRT 的示例测试:
class GenericHttpTest: XCTestCase {
var sut: Repository!
var mockHttpClient: MockHttpClient!
override func setUp() {
mockHttpClient = MockHttpClient()
sut = Repository(httpClient: mockHttpClient)
}
let test_mocked_data_stub = DataModelStruct(args: DataModelStruct.InsideModelStruct(foo1: "bar"))
func test_should_return_mocked_data_from_mock_http_client() {
mockHttpClient.stubbedMakeRequestResult = Observable.just(test_mocked_data_stub)
let response = try! sut.getFooBar().toBlocking().first()
XCTAssertEqual(response, test_mocked_data_stub)
}
}
Run Code Online (Sandbox Code Playgroud)
由于泛型在 Swift 中是不变的Observable<Any>,因此永远不会转换为Observable<T>,除非T是Any。这就是导致崩溃的原因,因为当您将值分配给 时stubbedMakeRequestResult,具体Observable会转换为Observable<Any>,并且从这里开始没有转折点。
为避免这种情况,您可以做的是创建stubbedMakeRequestResult一个Any,因为这不会在幕后进行任何转换。一个小问题是您失去了类型安全和推理,但您可以通过函数修复此存根:
class MockHttpClient: GenericHttpClientInterface {
...
var stubbedMakeRequestResult: Any!
func stubMakeRequestResult<T>(_ result: Observable<T>) {
stubbedMakeRequestResult = result
}
...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1304 次 |
| 最近记录: |