Motivation - ThorbenKuck/MockK-Method-Probing GitHub Wiki
The Issue
When we are trying to test asynchronous methods, we have a lot of hurdles to overcome.
Triggering the execution, awaiting the response, verifying asynchronously constructed results and and and.
The first and the last named problems have multiple solutions, already battle tested and mostly influenced by the business cases we try to implement. We might for example have a general messaging approach for sending those messages and a repository approach to fetch data from the database.
But how can we now ensure that the asynchronously executed code is for sure finished and ready to be used.
Using spin lock approaches
One approach would be, to look up, whether or not the data is set in the database. Then, if it is present to continue, otherwise to wait again.
For example with something like awaitlity
It would look something like this:
@Test
fun exampleTest() {
// Arrange
...
// Act
sender.publishMessage(/* The message the system expects */);
// Assert
await().atMost(5, SECONDS).until { repository.findById(/* id */).isPresent };
...
}
So, what exactly are we ensuring right here? We ensure right here that we wait until the repository returns data for our id. What could go wrong with that?
Well, we don't know that the data is the correct one. If we for example test a usecase which first creates and then updates the entity, at what point did this method right here exit? Is this the freshly created instance or already the updated one?
What if the transaction border shifted ever so slightly and we flush data to the database multiple times in the same process?
In such scenarios our test will fail, even though everything is okay. But not always. It might happen that the Test Thread is faster or slower and the Executing Thread picks up to early/to late. Maybe one time the create is finished when evaluating the condition and another time the update is finished?
Testing asynchronous code in this way requires us to write extensive conditions to ensure that everything is as we expect it to be. Now, the only issue is, that we never can ensure everything is as we expect it to be. There always might be a condition that we did not think about or just deemed to be to improbable.
Using Business Locks
What we really want is, to ensure that a specific method has been called. This is exactly what we will focus on in this library and for further explanation you can have a look into this article