Given the following method that contains a Task.
self.interactor
is mocked.
func submitButtonPressed() {
Task {
await self.interactor?.fetchSections()
}
}
How can I write a test to verify that the fetchSections() was called from that method?!
My first thought was to use expectations and wait until it is fulfilled (in mock’s code).
But is there any better way with the new async/await?
5
Answers
Ideally, as you imply, your
interactor
would be declared using a protocol so that you can substitute a mock for test purposes. You then consult the mock object to confirm that the desired method was called. In this way you properly confine the scope of the system under test to answer only the question "was this method called?"As for the structure of the test method itself, yes, this is still asynchronous code and, as such, requires asynchronous testing. So using an expectation and waiting for it is correct. The fact that your app uses async/await to express asynchronousness does not magically change that! (You can decrease the verbosity of this by writing a utility method that creates a BOOL predicate expectation and waits for it.)
I answered a similar question in this post: https://stackoverflow.com/a/73091753/2077405
Basically, given code defined like this:
and the
DataManagerProtocol
is defined as:a mock/fake implementation can be defined:
Implementing the unit test should go like this:
Hope this makes sense?
I don’t know if you already find a solution to your question, but here is my contribution to other developers facing the same problem.
I was in the same situation as you, and I solved the problem by using Combine to notify the tested class that the method was called.
Let’s say that we have this method to test:
We should start by mocking the interaction:
Now that we have our mocked interactor we can start write unit test:
There was one solution suggested here (@andy) involving injecting the
Task
. There’s a way to do this by thefunc
performing the task returning theTask
and allows a test toawait
thevalue
.(I’m not crazy about changing a testable class to suit the test (returning the
Task
), but it allows to testasync
withoutNSPredicate
or setting some arbitrary expectation time (which just smells)).Late to the party but this worked for me