ios – Swift – 使用XCTest来测试包含闭包的函数

ios – Swift – 使用XCTest来测试包含闭包的函数,第1张

概述我对 Swift相当新,我正在尝试编写一个单元测试(使用XCTest)来测试以下函数: func login(email: String, password: String) { Auth.auth().signIn(withEmail: email, password: password) { (user, error) in if let _error = erro 我对 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")        }    }}

我的研究已经确定我需要使用XCTestExpectation功能,因为默认情况下XCTest同步执行意味着它不会等待闭包完成运行(如果我错了请纠正我).

什么让我失望的是我如何测试登录功能,因为它本身调用异步函数Auth.auth().signIn().我正在尝试测试signIn是否成功.

如果这已经得到回答,我很抱歉,但我找不到直接解决这个问题的答案.

谢谢

更新:

在答案和进一步研究的帮助下,我通过登录功能进行了修改,以使用转义闭包:

func login(email: String,password: String,completion: @escaPing(Bool)->())  {    Auth.auth().signIn(withEmail: email,error) in        if let _error = error {            print(_error.localizedDescription)            completion(false)        } else {            self.performSegue(IDentifIEr: "loginSeg")            completion(true)        }    }}

然后我按以下方式测试:

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)    }}

我的测试功能现在成功测试登录功能.

希望这有助于某人,因为它让我感到难过一段时间:)

解决方法 对Auth的调用是一个架构边界.如果单元测试达到这样的边界,但是不要越过它们,则单元测试更快,更可靠.我们可以通过隔离协议背后的Auth单例来实现这一点.

我猜着signIn的签名.无论是什么,将其复制并粘贴到协议中:

protocol AuthProtocol {    func signIn(withEmail email: String,completion: @escaPing (String,NSError?) -> VoID)}

这可以作为完整Auth界面的一小部分,只占用您想要的部分.这是接口隔离原理的一个例子.

然后扩展Auth以符合此协议.它已经存在,所以一致性是空的.

extension Auth: AuthProtocol {}

现在在视图控制器中,将对Auth.auth()的直接调用解压缩到具有默认值的属性中:

var auth: AuthProtocol = Auth.auth()

请与此属性对话,而不是直接与Auth.auth()对话:

auth.signIn(withEmail: email,…etc…

这介绍了一个Seam.测试可以使用作为测试间谍的实现替换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,Foundation.NSError?) -> VoID) {        signInCallCount += 1        signInArgsEmail.append(email)        signInArgsPassword.append(password)        signInArgsCompletion.append(completion)    }}

测试可以将SpyAuth注入到视图控制器中,拦截通常用于Auth的所有内容.如您所见,这包括完成关闭.我会写的

>一个测试来确认调用计数和非闭包参数
>获得捕获的闭包并成功调用它的另一个测试.
>如果您的代码没有print(_)语句,我也会将其称为失败.

最后,还有segues的问题. Apple没有给我们任何单元测试方法.作为一种解决方法,您可以进行部分模拟.像这样的东西:

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)    }}

有了这个,你可以拦截调用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,"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))")    }}

绝对没有异步,所以没有waitForExpectations.我们捕获闭包,我们称之为闭包.

(像这样的东西将在iOS unit testing book I’m currently writing中深入讨论.)

总结

以上是内存溢出为你收集整理的ios – Swift – 使用XCTest来测试包含闭包的函数全部内容,希望文章能够帮你解决ios – Swift – 使用XCTest来测试包含闭包的函数所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1021300.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存