Method Barriers Basics - ThorbenKuck/MockK-Method-Probing GitHub Wiki

A MethodBarrier is a barrier, that blocks a Thread until another method has been called.

Principal

A barrier is simple. It bridges a potential asynchronous method to the test. All errors are transcribed from the method to the test, failing the test if any error happens in the code that should be executed. The barrier allows to detect methods call without relying on spin locks or busy waiting, making it thread safe and business safe.

Using a barrier

For tests, let's assume that we want to wait with a test until ExampleService#finish has been called with an id as a parameter.

For utilising this library, we need a spy or a mock to wrap our barrier around.

val service = ExampleService()
val serviceSpy = spyk(service)

Now, with this serviceSpy, we can create a barrier like this:

import de.thorbenkuck.mockk.barrier

val methodBarrier = barrier { serviceSpy.finish(any()) }

A method stub right here, will follow the same rules, as if we where to call every in mockk. Only if the correct match is called, the barrier will be released.

This barrier can then be tried to traverse by calling it like this:

methodBarrier.tryToTraverse()

How does this interfere with testing?

This method call methodBarrier.tryToTraverse() will block the testing thread, until the method serviceSpy.finish has been invoked and finished. There are certain thinks to keep in mind:

  • If the method serviceSpy.finish is not finished within 10 seconds after the methodBarrier.tryToTraverse has been called, the test fails
  • If the method serviceSpy.finish throws an exception, the test fails

Those parameters can be tweaked, which is explained in the next articles.

Interoparability with Spring and SpringMockK

If you want to test something and are running spring, you can do something like this:

class TestClass {
    @SpyKBean
    private lateinit var service: ExampleService

    @Test
    fun test() {
        // Arrange
        val barrier = barrier { service.finish(any()) }

        // Act
        // Start the async, for example using Kafka

        // Assert
        barrier.tryToTraverse()
    }
}

This makes it small, easy and quick to use