I wrote a unit test to test if my email validation regex works. This works well if I check one email address string in my test. This is my code which works:
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()
}
However, I have an array of email addresses to verify against and if I add a loop, I get the error: API violation - multiple calls made to -[XCTestExpectation fulfill]
I understand that this is due to the expectation being called more than specified.
I took some advice from this SO answer and added this code:
let waitExpectation = expectation(description: "testValidEmail_showsAlertWithSuccessMessage_whenLoginButtonIsTapped")
waitExpectation.expectedFulfillmentCount = validEmails.count
However, this still gives me the same error. This is my code with the loop
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()
}




