Reputation: 5069
I want to test a function which invokes other async function and I don't know how to write it. Function would go like this:
function(X x, Y y) {
x.doSomethingAsync().then((result) {
if (result != null) {
y.doSomething();
}
}
}
I would like to mock both X and Y, run X and than verify that y.doSomething()
gets invoked. However I do not know how to wait for x.doSomethingAsync()
to complete. I was thinking about doing some waiting before assertion but it doesn't seem like reliable solution.
Any help please? :)
Upvotes: 6
Views: 9390
Reputation: 1530
The accepted answer doesn't actually answer the original question. And some of the comments are misleading.
The real answer to the original question is to use
await untilCalled()
To test a function which calls an async function and prescribes the result with then, inside the test you can do:
function(mockX, mockY);
await untilCalled(mockY.doSomething());
verify(mockY.doSomething).called(1)
This will cause the test to wait for the async operation to complete and call the doSomething() function, and then you can verify the results.
Be careful, though, because if the function you're waiting for is never called, the test will wait forever. It's wise when using untilCalled to also set a timeout:
await untilCalled(untilCalled(mockY.doSomething())).timeout(Duration(seconds: 1));
This way, if the function you're waiting for doesn't get called, the test will continue, and then fail.
Upvotes: 1
Reputation: 277037
You can use async/await
in dart. Which would simplify quite a lot your function :
function(DoSomething x, DoSomething y) async {
final result = await x.doSomethingAsync();
if (result != null) {
y.doSomething();
}
}
This way, the function will not complete until x.doSomething
has completed. You can then test your function using the same async/await
operators with an async test
.
You'd have this :
test('test my function', () async {
await function(x, y);
});
Okey, but how do I test if the functions got called ?
For this, you can use mockito which is a mock package for tests purposes.
Let's assume your x/y class is :
class DoSomething {
Future<Object> doSomethingAsync() async {}
void doSomething() {}
}
you could then use Mockito by mocking your class methods using :
// Mock class
class MockDoSomething extends Mock implements DoSomething {
}
finally you could use that mock inside your test by doing :
test('test my function', () async {
final x = new MockDoSomething();
final y = new MockDoSomething();
// test return != null
when(x.doSomethingAsync()).thenReturn(42);
await function(x, y);
verifyNever(x.doSomething());
verify(x.doSomethingAsync()).called(1);
// y.doSomething must not be called since x.doSomethingAsync returns 42
verify(y.doSomething()).called(1);
verifyNever(y.doSomethingAsync());
// reset mock
clearInteractions(x);
clearInteractions(y);
// test return == null
when(x.doSomethingAsync()).thenReturn(null);
await function(x, y);
verifyNever(x.doSomething());
verify(x.doSomethingAsync()).called(1);
// y must not be called this x.doSomethingAsync returns null here
verifyZeroInteractions(y);
});
Upvotes: 8