Ree*_*o96 6 testing xcode ios xctest swift
我对Swift相当新,我正在尝试编写一个单元测试(使用XCTest)来测试以下函数:
func login(email: String, password: String) {
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
if let _error = error {
print(_error.localizedDescription)
} else {
self.performSegue(identifier: "loginSeg")
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的研究已经确定我需要使用XCTestExpectation功能,因为默认情况下XCTest同步执行意味着它不会等待闭包完成运行(如果我错了请纠正我).
什么让我失望是我如何测试登录功能,因为它本身调用异步函数Auth.auth().signIn().我正在尝试测试signIn是否成功.
如果这已经得到回答,我很抱歉,但我找不到直接解决这个问题的答案.
谢谢
更新:
在答案和进一步研究的帮助下,我通过登录功能进行了修改,以使用转义闭包:
func login(email: String, password: String, completion: @escaping(Bool)->()) {
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
if let _error = error {
print(_error.localizedDescription)
completion(false)
} else {
self.performSegue(identifier: "loginSeg")
completion(true)
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后我按以下方式测试:
func testLoginSuccess() {
// other setup
let exp = expectation(description: "Check Login is successful")
let result = login.login(email: email, password: password) { (loginRes) in
loginResult = loginRes
exp.fulfill()
}
waitForExpectations(timeout: 10) { error in
if let error = error {
XCTFail("waitForExpectationsWithTimeout errored: \(error)")
}
XCTAssertEqual(loginResult, true)
}
}
Run Code Online (Sandbox Code Playgroud)
我的测试功能现在成功测试登录功能.
希望这有助于某人,因为它让我感到难过一段时间:)
对Auth的调用是一个体系结构边界。如果单元测试达到了这样的界限,但不要越过它们,则更快,更可靠。我们可以通过在协议后面隔离Auth单例来做到这一点。
我正在猜测的签名signIn。无论是什么,都将其复制并粘贴到协议中:
protocol AuthProtocol {
func signIn(withEmail email: String, password: String, completion: @escaping (String, NSError?) -> Void)
}
Run Code Online (Sandbox Code Playgroud)
这只是完整Auth接口的一小部分,仅包含您想要的部分。这是接口隔离原理的一个示例。
然后扩展Auth以符合此协议。它已经这样做了,因此一致性为空。
extension Auth: AuthProtocol {}
Run Code Online (Sandbox Code Playgroud)
现在,在视图控制器中,将直接调用提取Auth.auth()到具有默认值的属性中:
var auth: AuthProtocol = Auth.auth()
Run Code Online (Sandbox Code Playgroud)
与该属性交谈,而不是直接与Auth.auth():
auth.signIn(withEmail: email, …etc…
Run Code Online (Sandbox Code Playgroud)
这引入了接缝。测试可以替换auth为测试间谍的实现,并记录signIn调用方式。
final class SpyAuth: AuthProtocol {
private(set) var signInCallCount = 0
private(set) var signInArgsEmail: [String] = []
private(set) var signInArgsPassword: [String] = []
private(set) var signInArgsCompletion: [(String, Foundation.NSError?) -> Void] = []
func signIn(withEmail email: String, password: String, completion: @escaping (String, Foundation.NSError?) -> Void) {
signInCallCount += 1
signInArgsEmail.append(email)
signInArgsPassword.append(password)
signInArgsCompletion.append(completion)
}
}
Run Code Online (Sandbox Code Playgroud)
一个测试可以将SpyAuth注入到视图控制器中,拦截通常会进入Auth的所有内容。如您所见,其中包括完成关闭。我会写
print(_)声明,我也会失败地称呼它。最后,还有问题。苹果公司没有给我们任何方式对其进行单元测试。解决方法是,可以进行部分模拟。像这样:
final class TestableLoginViewController: LoginViewController {
private(set) var performSegueCallCount = 0
private(set) var performSegueArgsIdentifier: [String] = []
private(set) var performSegueArgsSender: [Any?] = []
override func performSegue(withIdentifier identifier: String, sender: Any?) {
performSegueCallCount += 1
performSegueArgsIdentifier.append(identifier)
performSegueArgsSender.append(sender)
}
}
Run Code Online (Sandbox Code Playgroud)
这样,您可以拦截对的呼叫performSegue。这不是理想的,因为它是一种遗留代码技术。但这应该可以帮助您入门。
final class LoginViewControllerTests: XCTestCase {
private var sut: TestableLoginViewController!
private var spyAuth: SpyAuth!
override func setUp() {
super.setUp()
sut = TestableLoginViewController()
spyAuth = SpyAuth()
sut.auth = spyAuth
}
override func tearDown() {
sut = nil
spyAuth = nil
super.tearDown()
}
func test_login_shouldCallAuthSignIn() {
sut.login(email: "EMAIL", password: "PASSWORD")
XCTAssertEqual(spyAuth.signInCallCount, 1, "call count")
XCTAssertEqual(spyAuth.signInArgsEmail.first, "EMAIL", "email")
XCTAssertEqual(spyAuth.signInArgsPassword.first, "PASSWORD", "password")
}
func test_login_withSuccess_shouldPerformSegue() {
sut.login(email: "EMAIL", password: "PASSWORD")
let completion = spyAuth.signInArgsCompletion.first
completion?("DUMMY", nil)
XCTAssertEqual(sut.performSegueCallCount, 1, "call count")
XCTAssertEqual(sut.performSegueArgsIdentifier.first, "loginSeg", "identifier")
let sender = sut.performSegueArgsSender.first
XCTAssertTrue(sender as? TestableLoginViewController === sut,
"Expected sender \(sut!), but was \(String(describing: sender))")
}
}
Run Code Online (Sandbox Code Playgroud)
这里绝对没有异步,所以没有waitForExpectations。我们捕获闭包,我们称为闭包。
(我通过示例 “ iOS单元测试:使用Swift的XCTest技巧和技巧”更详细地介绍了此类内容。)
| 归档时间: |
|
| 查看次数: |
1060 次 |
| 最近记录: |