skip to Main Content

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


  1. Chosen as BEST ANSWER

    enter image description here

    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?


  2. You don’t need to use an XCTestExpectation for this by the looks of it. This should work.

    func test_checkNumber_success() async  {
            let viewModel = PrimeNumberCheckViewModel(service: MockPrimeNumberService())
            XCTAssertEqual(viewModel.isPrime, false)
            XCTAssertEqual(viewModel.validationInProgress, false)
            let res = await viewModel.checkNumber(3)
            XCTAssertEqual(viewModel.isPrime, true)
            XCTAssertEqual(viewModel.validationInProgress, false)
        }
    

    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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search