You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环测试异步函数时XCTestExpectation多次调用报错,调整期望次数无效

邮箱正则验证单元测试批量执行问题

我编写了用于验证邮箱正则表达式的单元测试,单个邮箱测试时运行正常,代码如下:

func testValidEmail_showsAlertWithSuccessMessage_whenLoginButtonIsTapped() throws {
    // Given: Login view model configured with the mock email regex specified in the appConfigResponse.json
    let appConfigService = try XCTUnwrap(createDefaultMockConfigService())
    
    // Given: A list of valid email addresses
    let validEmails = generateValidEmails()
    
    let waitExpectation = expectation(description: "testValidEmail_showsAlertWithSuccessMessage_whenLoginButtonIsTapped")
    
    appConfigService.loadAppConfig { [weak self] _ in
        guard let self else { return }
        
        let appInfoManager = AppInfoManager(service: appConfigService)
        let viewModel = LoginViewModel(appInfoManager: appInfoManager)
        
        viewModel.$shouldShowEmailValidationAlert
            .drop(while: { $0 == false })
            .sink { _ in
                // Then: Verify the success message is displayed in the alert
                XCTAssertEqual(viewModel.emailValidationAlertText,
                               LoginViewModel.StringConstants.validEmailTitle)
                
                waitExpectation.fulfill()
            }
            .store(in: &self.cancellables)
        
        // When: Entering a valid email address and then tapping on the login button
        viewModel.emailFieldViewModel.text = validEmails.randomElement()!
        viewModel.didTapLoginButton()
    }
    
    waitForExpectations()
}

但当我需要批量验证一个邮箱地址数组,添加循环后出现错误:API violation - multiple calls made to -[XCTestExpectation fulfill]。我明白这是因为期望被多次调用。

我尝试设置期望的预期完成次数为邮箱数组的长度,代码如下:

let waitExpectation = expectation(description: "testValidEmail_showsAlertWithSuccessMessage_whenLoginButtonIsTapped")
waitExpectation.expectedFulfillmentCount = validEmails.count

但问题仍然存在,我的循环测试代码如下:

func testValidEmail_showsAlertWithSuccessMessage_whenLoginButtonIsTapped() throws {
    // Given: Login view model configured with the mock email regex specified in the appConfigResponse.json
    let appConfigService = try XCTUnwrap(createDefaultMockConfigService())
    
    // Given: A list of valid email addresses
    let validEmails = generateValidEmails()
    
    let waitExpectation = expectation(description: "testValidEmail_showsAlertWithSuccessMessage_whenLoginButtonIsTapped")
    waitExpectation.expectedFulfillmentCount = validEmails.count
    
    appConfigService.loadAppConfig { [weak self] _ in
        guard let self else { return }
        
        let appInfoManager = AppInfoManager(service: appConfigService)
        let viewModel = LoginViewModel(appInfoManager: appInfoManager)
        
        for validEmail in validEmails {
            viewModel.$shouldShowEmailValidationAlert
                .drop(while: { $0 == false })
                .sink { _ in
                    // Then: Verify the success message is displayed in the alert
                    XCTAssertEqual(viewModel.emailValidationAlertText,
                                   LoginViewModel.StringConstants.validEmailTitle)
                    
                    waitExpectation.fulfill()
                }
                .store(in: &self.cancellables)
            
            // When: Entering a valid email address and then tapping on the login button
            viewModel.emailFieldViewModel.text = validEmail
            viewModel.didTapLoginButton()
        }
    }
    
    waitForExpectations()
}

内容的提问来源于stack exchange,提问作者Shawn Frank

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:35:54