Is it possible to unit test closures with context?

时间:2017-10-12 09:36:54

标签: java unit-testing mocking closures anonymous-function

With closures it comes natural to make use of the context that is being enclosed. For example, consider the following basic code:

public class Service
{
    public void serve(final Consumer<SomeType> callback)
    {
        final SomeType obj = obtainASomeTypeSomehow();
        callback.accept(obj);
    }
}

public class MyClass
{
    public void myMethod()
    {
        final Context context = obtainContextSomehow();
        service.call(o -> doSomethingWithContext(context));
    }
}

Now, to unit test code like this, I would start extracting the anonymous function into its own class, implementing Consumer, and inject it into MyClass, so that it can be mocked.

final Service service = mock(Service.class);
final Consumer<SomeType> callback = mock(Consumer.class);
final MyClass sut = new MyClass(service, callback);
sut.myMethod();
// verify something on the mocked callback

The problem, now, comes with the actual implementation of the Consumer: in the original implementation with the closure, it was directly using the context of the enclosing method, but this is of course not available anymore after I extract it to its own class.

One solution could be to inject that context into the constructor of the callback class, and inject into the main class a factory that creates the callback on the fly with the given context:

final Service service = mock(Service.class);
final Consumer<SomeType> callback = mock(Consumer.class);
final CallbackFactory factory = mock(CallbackFactory.class);
when(factory.create(any()).thenReturn(callback);

final MyClass sut = new MyClass(service, factory);
sut.myMethod();
// verify something on the mocked callback

Then of course I can also write a unit test for the Consumer implementation, taking the context as a constructor argument.

This could work, but wouldn't all this extracting and injecting go against the whole purpose of using closures? I mean, closures are handy because you can drop a few lines of code in, directly referring to the surrounding context. Is it even possible to unit test code with closures and enclosed contexts, or do I need to always fall back to the more traditional style?

Looking around, this was basically the general suggestion that I saw being given, in addition to moving to a higher (less "unit") level of testing where you avoid mocking too much stuff.

0 个答案:

没有答案