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:
Here is the screenshot of the error ..