Java unit testing: the easiest way to test if a callback is invoked

Lyubomyr Shaydariv picture Lyubomyr Shaydariv · Dec 7, 2014 · Viewed 11.5k times · Source

I often work with methods that accept callbacks, and callbacks seem to be somewhat hard to test. Let's consider the following scenario, if there's a method that accepts a callback with a single method (for simplicity, I assume the testing method is synchronous), the following boilerplate could be written just to ensure that a callback method is invoked:

@Test
public void testMethod() {
    final boolean[] passed = {false};
    method(new Callback() {
        @Override
        public void handle(boolean isSuccessful) {
            passed[0] = isSuccessful;
        }
    });
    assertTrue(passed[0]);
}

It looks like a surrogate. I would like to know: is there a more elegant way to test such code to make the code above look more like the pseudo-code below?

@Test
public void testMethod() {
    // nothing explicit here, implicit boolean state provided by a test-runner
    method(new Callback() {
        @Override
        public void handle(boolean isSuccessful) {
            if ( isSuccessful ) {
                pass(); // not sure how it should look like:
                        // * an inherited method that sets the state to "true"
                        // * or an object with the pass method
                        // * whatever
                        // but doesn't exit testMethod(), just sets the state
            }
        }
    });
    // nothing explicit here too:
    // test runner might check if the state is changed to true
    // otherwise an AssertionError might be thrown at the end of the method implicitly
}

A little cleaner. Is it possible in JUnit, TestNG or any other testing framework? Thanks!


UPDATE

Sorry, I seem to have asked a vague question that doesn't really meets what I wanted to ask. I basically meant any code (not necessarily a callback) that might be invoked if certain conditions are satisfied just to set the result state to true. Simply speaking, I just want to get rid of the initial boolean[] passed and the final assertTrue(passed[0]) assuming that they are some kind of prologue and epilogue respectively and assuming that the initial state is set to false so the pass() should be invoked to set the state to true. No matter how the passed[0] is set to true, no matter where from. But unfortunately I have asked this question using the context of callbacks, however this is just an option, not a requirement. Thus the title of the question does not reflect what I really wanted to ask, but before the update some answers have been posted.

Answer

fge picture fge · Dec 7, 2014

This is typically what a mocking framework can do for you.

With Mockito for instance:

// imports ommited for brevity
@Test
public void callbackIsCalled()
{
    final CallBack callBack = mock(CallBack.class);
    method(callBack);

    verify(callBack, only()).handle(any());
}

Of course, this is an example of verification mode (only()) and value matcher (any()). You can do more...

(other mocking frameworks exist, but I personally find Mockito the easiest to use, in addition to being one of the most powerful)