Swift UI Search app view model return nil error on unit testing

100 Views Asked by At

I am trying to test the search function. When I enter the text App, it should return 3 records, but instead it returns nil and showing error testSearcFruit_success_WithLatter_A(): XCTAssertEqual failed: ("0") is not equal to ("3") - Total is empty I thought there might be problems with using debounce and delay and I added the delay but still it showing the same error.

I tried the following code to make the delay … but still some problems.

 DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            let resultCount = self.viewModel.filterFruits(text: "App", fruit: self.filteredFruit)
            XCTAssertEqual(resultCount.count ,3, "Total is empty")
            expectation.fulfill()
        }

My view model code:

final class FruitListViewModel: FruitListViewModelType, ObservableObject {
    
    private let service: Service
    @Published private(set) var fruits = [Fruits]()
    @Published var filteredFruit: [Fruits] = []
    @Published var searchText: String = ""
    private var cancellable = Set<AnyCancellable>()

    init(service:Service = ServiceImpl()) {
        self.service = service
        fetchFruit()
    }
    
    func fetchFruit() {
        let client = ServiceClient(baseUrl:EndPoints.baseUrl.rawValue, path:Path.fruitList.rawValue, params:"", method:"get")
        
        service.fetchData(client: client, type: [Fruits].self)
            .receive(on: RunLoop.main)
            .sink { completion in
                switch completion {
                case let .failure(error):
                    print(error)
                default:
                    break
                }
            } receiveValue: { response in
                self.fruits = response
            }.store(in: &cancellable)
        
        $searchText
            .combineLatest($fruits)
            .debounce(for: .seconds(0.5), scheduler: RunLoop.main)
            .map(filterFruits)
            .sink { [weak self] (filterList) in
                self?.filteredFruit = filterList
            }
            .store(in: &cancellable)
    }
    public func filterFruits(text: String, fruit: [Fruits]) -> [Fruits] {

        guard !searchText.isEmpty else {
            return fruit
        }
        let lowercasedText = searchText.lowercased()
        let filterFruitList = fruit.filter { (fruit) -> Bool in
            fruit.name.lowercased().contains(lowercasedText) ||
            fruit.genus.lowercased().contains(lowercasedText) ||
            fruit.family.lowercased().contains(lowercasedText)
        }
        return filterFruitList
    }
}

The mock service code:

class MockService: Service {
    
    var responseFileName = ""
    
    func fetchData<T>(client: FruitsDemoSwiftUI.ServiceClient, type: T.Type) -> AnyPublisher<T,ServiceError> where T : Decodable, T : Encodable {
        
        let bundle = Bundle(for: MockService.self)
        guard let url = bundle.url(forResource: responseFileName, withExtension:"json"),
              let data = try? Data(contentsOf: url) else {
            return Fail(outputType: type, failure: ServiceError.requestNotCreated(message: Constants.requestNotCreated)).eraseToAnyPublisher()
        }
        do {
            let decodeObject = try JSONDecoder().decode(T.self, from: data)
            return Just(decodeObject)
                .setFailureType(to: ServiceError.self)
                .eraseToAnyPublisher()
        } catch {
            return Fail(outputType: type, failure: ServiceError.requestNotCreated(message: Constants.requestNotCreated))
                .eraseToAnyPublisher()
        }

    }
}

My testing code :

import XCTest
@testable import FruitsDemoSwiftUI

final class FruitsDemoSwiftUISearchTests: XCTestCase {
    var mockService: MockService!
    var viewModel: FruitListViewModel!
     var filteredFruit: [Fruits] = []

    override func setUp() {
        mockService = MockService()
        viewModel = FruitListViewModel(service: mockService)
    }

    override func tearDownWithError() throws {
        viewModel = nil
    }
    
    func testSearcFruit_success_WithLatter_A() {
        let expectation = expectation(description: "Wait for async code to complete")
        mockService.responseFileName = "FruitSuccessResponse"
        viewModel.fetchFruit()
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            let resultCount = self.viewModel.filterFruits(text: "App", fruit: self.filteredFruit)
            XCTAssertEqual(resultCount.count ,3, "Total is empty")
            expectation.fulfill()
        }
        wait(for: [expectation], timeout: 2.0)
    }
}

The result on debug mode:

debug result

Here is the screenshot of the error ..

error

0

There are 0 best solutions below