I am trying to write async/awit unit test i have tried ample of combos to make this test pass but for some reason when the call happens it steps into the the viewModel checkNumber() executes the first two lines of code and thats it, it only works that way intest not when I do integration test tho. i need help to figure why the do block in my viewModel isbeing skipped by the test case that i am writting
func test_checkNumber_success() async {
let expectation = XCTestExpectation(description: "CheckNumber completes successfully")
viewModel = PrimeNumberCheckViewModel(service: MockPrimeNumberService())
XCTAssertEqual(viewModel.isPrime, false)
XCTAssertEqual(viewModel.validationInProgress, false)
let res = await viewModel.checkNumber(3)
expectation.fulfill()
XCTAssertEqual(viewModel.isPrime, true)
XCTAssertEqual(viewModel.validationInProgress, false)
wait(for: [expectation], timeout: 0.05) // Adjust the timeout as needed
}
final class PrimeNumberCheckViewModel: PrimeNumberCheckProtocol {
@Published private(set) var validationInProgress = false
@Published var status = "checking ready to get started"
@Published private(set)var isPrime: Bool = false
private let service: PrimeServiceProtocol
private var validationTask: Task<Void, Never>?
init(service: PrimeServiceProtocol) {
self.service = service
}
@MainActor
func checkNumber(_ number: Int) async {
self.validationInProgress = true
self.status = "Checking (number) in progress"
validationTask?.cancel()
validationTask = Task {
var res = false
do {
res = try await service.checkNumber(number)
print("this is res: (res)")
updateStatus(res, number)
self.isPrime = res
} catch {
//TODO: handle error scenario case
print(error)
}
self.validationInProgress = false
}
}
}
this is the service that i am injectig in my viewModel
class MockPrimeNumberService: PrimeServiceProtocol {
@MainActor
func checkNumber(_ number: Int) async throws -> Bool{
try await Task.sleep(nanoseconds: 2 * 1_000_000_000)
// Check if the number is less than 2
if number <= 1 {
return false
}
// Check for divisibility from 2 to the square root of the number
for i in 2..<Int(Double(number).squareRoot()) + 1 {
if number % i == 0 {
return false
}
}
return true
}
2
Answers
I have tried the solution above, however the issue still persists, to help you help me here this are the errors that I get for some reason the test just runs two lines of code to set the values of isPrime, and validationInProgress and then exits that is. why the test is not passing why is that happening?
You don’t need to use an
XCTestExpectation
for this by the looks of it. This should work.It looks though like you’re using a shared instance of your view model for every test, which might be leading to some unexpected state changes. I would recommend (and have in my answer above) creating a new instance for each test so that you can assert that a view model does very specific things without the risk of unexpected state changes.