I need to test a class that is using another interface as a dependency injection with a lambda Consumer.
@Builder
public class Interactor {
private final Gateway gateway;
void process(String message, Consumer<String> response){
gateway.process(message, uuid -> {
response.accept(uuid.toString());
});
}
}
The dependency is defined like so:
public interface Gateway {
void process(String message, Consumer<UUID> uuid);
}
How would I mock the Gateway so I can provide a UUID value response to my test?
This is what I have tried so far:
@Test
void whillReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = Mockito.mock(Gateway.class);
Mockito.when(gateway.process("ignored", uuid1 -> {return uuid;}));
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
How should I provide the return value to the consumer?
For now I ended up mocking my own inner class without Mockito.
class InteractorTest {
@Test
void whillReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = GatewayMock.builder().value(uuid).build();
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
@Builder
private static class GatewayMock implements Gateway {
private final UUID value;
@Override
public void process(String message, Consumer<UUID> uuid) {
uuid.accept(value);
}
}
}
is to verify the result of the logic of Interactor#process
, which takes a Consumer<String>
and basically just calls Gateway#process
with a Consumer<UUID>
implementation that calls back to the Consumer<String>
parameter.
Ideally you want to do this just by calling Interactor#process
and verifying the call to the Consumer<String>
you supply.
that it is up to the implementator of Gateway
to trigger the Consumer<UUID>
(and consequently the Consumer<String>
). So you need to inject an implementation of Gateway
that does just that.
along the lines of the answer you provided (i.e. using a Fake Object instead of a Mock), unless there is a real implementation of Gateway
in your production code that you can easily use instead (but I assume you'd be doing that already if that was the case).
Can you do it with Mockito? Sure, you can call methods on a mock object's method arguments, as shown in this answer: https://stackoverflow.com/a/16819818/775138 - but why would you go there if you can provide a sufficient Gateway
implementation in a single line:
Gateway gw = (message, consumer) -> consumer.accept(uuid);
where uuid
is the UUID instance that you constructed before. So no need to declare a static inner class just for this.
there is an important issue with your assertion: if Interactor
does nothing at all instead of calling the Gateway
, the Consumer<String>
you provide (containing the assertion) won't get triggered, so your test will pass! Just assign the value to a member variable of your test class, and assert on that outside the lambda.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With