I'm working on an iOS app (utilizing Swift, XCTest, and Combine) trying to test a function within my view model, which is calling and setting a sink
on a publisher. I'd like to test the view model, not the publisher itself. I really don't want to use DispatchQueue.asyncAfter(
because theoretically I don't know how long the publisher will take to respond. For instance, how would I test XCTAssertFalse(viewModel.isLoading)
class ViewModel: ObservableObject {
@Published var isLoading: Bool = false
@Published var didError: Bool = false
var dataService: DataServiceProtocol
init(dataService: DataServiceProtocol) {
self.dataService = dataService
}
func getSomeData() { // <=== This is what I'm hoping to test
isLoading = true
dataService.getSomeData() //<=== This is the Publisher
.sink { (completion) in
switch completion {
case .failure(_):
DispatchQueue.main.async {
self.didError = true
}
case .finished:
print("finished")
}
DispatchQueue.main.async {
self.isLoading = false
}
} receiveValue: { (data) in
print("Ok here is the data", data)
}
}
}
I'd like to write a test that might look like:
func testGetSomeDataDidLoad() {
// this will test whether or not getSomeData
// loaded properly
let mockDataService: DataServiceProtocol = MockDataService
let viewModel = ViewModel(dataService: mockDataService)
viewModel.getSomeData()
// ===== THIS IS THE PROBLEM...how do we know to wait for getSomeData? ======
// It isn't a publisher...so we can't listen to it per se... is there a better way to solve this?
XCTAssertFalse(viewModel.isLoading)
XCTAssertFalse(viewModel.didError)
}
Really hoping to refactor our current tests so we don't utilize a DispatchQueue.asyncAfter(