Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test callback logic?

More complete question is, given a dependency that expects a callback as a parameter, how do I write a unit test that covers the callback logic and still manage to mock up the dependency?

public class DoStuff {
    public void runThis(Runnable callback) {
        // call callback
    }
}

public class ClassUnderTest {
    private DoStuff stuffToDo;

    public void methodUnderTest() {
        this.stuffToDo.runThis(/*a runnable with some logic*/)
    }
}

In the example above, I would mock stuffToDo since I should verify calls and mock outputs of method calls. However, mocking runThis results in the callback logic not being tested. Furthermore, callback logic seems like it should be private so I wouldn't expect to test it directly; perhaps that is a misconception on my part.

Since callbacks are used rather extensivly, I would expect there to be a common method for testing them but I haven't found it.

like image 336
Andrew White Avatar asked Aug 22 '11 13:08

Andrew White


2 Answers

You can't in a single test. If you mock something, its mocked, meaning it can only verify arguments and simulate return values (that you configure in the test).

Indeed, the entire point of mocking something is to test what uses the mock in isolation. If you want a unit test of DoStuff, you don't want to have to worry about using some callback implementation that might or might not be working. You mock the callback so you don't have to worry about it.

You can still have good tests by testing the callback code in isolation, and testing the callback user in isolation (using a mock for the callback) and perhaps by throwing an integration test in for good measure, where you use the fully configured component as a whole.

like image 147
hvgotcodes Avatar answered Oct 18 '22 22:10

hvgotcodes


Here basically you want to test the class DoStuff. That means you need to unti-test all the methods inside DoStuff, right?. So in this case, what you need to do is, instead of mocking stuffToDo itself, inject a mocked Runnable into stuffToDo. And then check whether your runnable was successfully executed or not.

But if you do have other functionalities in the class, you may have separate test and mock them out.

like image 41
Suraj Chandran Avatar answered Oct 18 '22 23:10

Suraj Chandran