Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a convenient way to pause the execution of suspend functions on a mock temporarily #102

Open
dalewking opened this issue Apr 29, 2024 · 0 comments

Comments

@dalewking
Copy link

dalewking commented Apr 29, 2024

When i created my own function mocking layer on top of Mockative 1.4.1 i created a simple way to block the return of a suspend function so that you can check a condition that only exists while the suspend function has not finished. For example, let's say you had a case like this:

suspend fun functionToTest() {
    isWorking = true
    mockedSuspendFunction()
    isWorking = false
}

and i want to test that isWorking gets set to true. I need to block the execution of mockedSuspendFunction and then resume it.

I can certainly do that manually by setting up the expectations all over again like

     val deferred = CompletableDeferred<Unit>()

     coEvery { mockedSuspendFunction() }
        .invokes { _ ->
            deferred.await()
            // repeat the normal set up all over again
        }

    functionToTest()

    assertTrue(isWorking)

    deferred.complete(Unit)

    assertFalse(isWorking)

That is a lot of ceremony and if the normal set up for the mock is complex is very verbose.

What i had done in my my Mockative wrapper for functions was to allow you to write that like this:

    mockedSuspendFunction.whilePaused {
        functionToTest()
        assertTrue(isWorking)
    }

    assertFalse(isWorking)

How could this be done with Mockative. I propose these additions to Mockable:

    private var deferred: CompletableDeferred<Unit>? = null

    /**
     * Provides a way to have the return from the function to be delayed
     * to verify status while the suspend call would be in progress
     */
    internal fun pause() { deferred = CompletableDeferred() }

    /**
     * Resume any blocked calls to the function
     */
    internal fun resume() { deferred?.complete(Unit) }

then in Mockable.suspend on all return and throws add a .also { deferred?.await() }

Then the definition of whilePaused is:

   fun <T: Any, R> T.whilePaused(block: () -> R) =
        with(Mockable(this)) {
            pause()

            try {
                block()
            } finally {
                resume()
            }
        }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant