swift - 如何快速为方法编写单元测试,返回通过调用模拟类方法获得的响应的承诺?
问题描述
我正在快速为类的方法编写单元测试。这些方法调用为单元测试模拟的类方法。方法返回带有从模拟的静态/类方法获得的响应的承诺。
NetworkAuthProtocol:-
protocol NetworkAuthProtocol {
static func httpGet(_ url: String, completionHandler complete: @escaping(Any?, Error?) -> Void)
static func httpDelete(_ url: String, completionHandler complete: @escaping (Any?, Error?) -> Void)
}
下面是使用类方法进行单元测试的模拟类:-
class NetworkAuthMock: NetworkAuthProtocol {
class func httpGet(_ url: String, completionHandler complete: @escaping(Any?, Error?) -> Void) {
complete(nil, Error)
}
class func httpDelete(_ url: String, completionHandler complete: @escaping (Any?, Error?) -> Void) {
complete(nil, Error)
}
}
以下是我正在为其编写单元测试的课程:-
class FetchDataAPIService {
var networkAuthDelegate: NetworkAuthProtocol.Type = NetworkAuth.self
func fetchUserData(userUrl: String) -> Promise<Any> {
return Promise<Any> { seal in
networkAuthDelegate.httpGet(userUrl) { (result, error) in
if error == nil {
seal.fulfill(result!)
} else {
seal.reject(error!)
}
}
}
}
func deleteUserData(userUrl: String) -> Promise<Any> {
return Promise<Any> { seal in
networkAuthDelegate.httpDelete(userUrl) { (_, error) in
if error == nil {
seal.fulfill(())
} else {
seal.reject(error!)
}
}
}
}
}
我编写的单元测试,在下面添加:-
class FetchDataAPIServiceTests: XCTestCase {
var fetchDataAPIService: FetchDataAPIService!
var result: String?
var error: Error?
override func setUp() {
super.setUp()
self.fetchDataAPIService = FetchDataAPIService()
self.fetchDataAPIService.networkAuthDelegate = NetworkAuthMock.self
self.error = nil
}
override func tearDown() {
super.tearDown()
}
func testFetchUserData() {
let expectation = XCTestExpectation(description: "test fetchUserData")
firstly {
self.fetchDataAPIService.fetchUserData(userUrl: "url")
}.done { (_) in
XCTFail("test failed")
}.catch { (error) in
XCTAssertNotNil(error)
expectation.fulfill()
}
wait(for: [expectation], timeout: 10.0)
}
func testDeleteUserData() {
let expectation = XCTestExpectation(description: "test deleteUserData")
firstly {
self.fetchDataAPIService.deleteUserData(userUrl: "url")
}.done { (_) in
XCTFail("test failed")
}.catch { (error) in
XCTAssertNotNil(error)
expectation.fulfill()
}
wait(for: [expectation], timeout: 10.0)
}
}
有了期望,测试孤立地通过,但一起失败。我尝试了其他方法,例如在 XCTAssert 语句之外添加 DispatchQueue.main.asyncAfter 。我还在 Mock 类的 httpGet 和 httpDelete 方法中添加了断点,控件永远不会到达那里。似乎没有任何效果。代码覆盖仅在单独运行测试时有效,但有时也会在 main.m 文件中测试构建崩溃。如何使所有测试成功并涵盖所有方法的测试覆盖率?
解决方案
看,这是静态函数的问题之一 - 您需要确保在每次测试之前/之后进行适当的清理,以确保您不会在测试之间造成隐含的依赖关系。
我建议改为使用实例方法切换到更多的 OOP 方法:
protocol NetworkAuthProtocol {
func httpGet(_ url: String, completionHandler complete: @escaping(Any?, Error?) -> Void)
func httpDelete(_ url: String, completionHandler complete: @escaping (Any?, Error?) -> Void)
}
class FetchDataAPIService {
let networkAuthDelegate: NetworkAuthProtocol
init(networkAuth: NetworkAuthProtocol) {
self.networkAuthDelegate = networkAuth
}
,并在您的测试中添加对配置要发送的响应的支持:
class TestsNetworkAuth {
var httpGetResult: (Any?, Error?) = (nil, nil)
var httpDeleteResult: (Any?, Error?) = (nil, nil)
func httpGet(_ url: String, completionHandler complete: @escaping(Any?, Error?) -> Void) {
complete(httpGetResult.0, httpGetResult.1)
}
func httpDelete(_ url: String, completionHandler complete: @escaping (Any?, Error?) -> Void) {
complete(httpDeleteResult.0, httpDeleteResult.1)
}
}
class FetchDataAPIServiceTests: XCTestCase {
var testsNetworkAuth = TestsNetworkAuth()
var fetchDataAPIService: FetchDataAPIService!
override func setUp() {
super.setUp()
fetchDataAPIService = FetchDataAPIService(networkAuth: testsNetworkAuth)
}
使用上述方法,您可以添加模拟各种结果数据和/或错误的各种测试。并且测试不会相互干扰,因为每个测试都有自己的TestsNetworkAuth
. 由于方法的静态性质,在原始方法中,测试是共享数据的。
推荐阅读
- visual-studio - .NET Core 发布和版本错误
- php - 脚本执行时打印
- date - 转换后,为什么 EPOCH 时间返回的日期比预期早 1 分钟 15 秒
- crm - 保存销售订单后更新库存数量
- eclipse-hono - 使用来自 Hono 的数据时出现问题
- html - 如何在输入中设置按钮?
- php - 如何在 Laravel 4.2 中编写多进程队列(配置了 supervisord)?
- rest - 用于上传 ear 文件的 BW REST API
- excel - 如何在excel中更改链接时自动运行宏
- typo3 - 如何为多域 TYPO3 v9 设置 baseVariants?