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.
Given that this is the sort of thing you're likely to need in several places, I would just create a named class to use for tests:
public class FakeCallback implements Callback {
private boolean wasSuccessful;
private boolean handleCalled;
@Override public void handle(boolean isSuccessful) {
this.wasSuccessful = isSuccessful;
handleCalled = true;
}
// Getters for fields above
}
You can then use something like:
// Arrange...
FakeCallback callback = new FakeCallback();
// Act...
method(callback);
// Assert
assertTrue(callback.wasHandleCalled());
assertTrue(callback.wasSuccessful());
You could absolutely use a mocking framework for this instead, but personally I find that often it's simpler to create a single fake implementation than set up mocks repeatedly. Both ways will work though.
See more on this question at Stackoverflow