I want to inject value to a private field annotated with @Value in my Junit5 unit test.
@Value("$(invoice.maxRetry)")
private maxRetry;
I referred this and used ReflectionTestUtils.setField which solved my problem by injecting a value but failed when verifying the no. of times the method get called.
MyClass:
public class MessageProcessor {
@Value("$(invoice.maxRetry)")
private maxRetry;
protected void handleMessage() {
if(retry > maxRetry) {
kafkaTemplate.sendMessage(msg);
}
}
TestClass:
@ExtendWith(MockitoExtension.class)
public class MessageProcessorTest {
@Mock
private kafkaTemplate kafkaTemplate;
@Mock
private MessageProcessor messageProcessor
@Test
test() {
ReflectionTestUtils.setField(messageProcessor, "maxRetry", "5");
doNothing().when(kafkaTemplate).sendMessage(any());
messageProcessor.handleMessage();
verify(kafkaTemplate).sendMessage(any());
}
}
Error running above test
org.mockito.exceptions.verification.TooManyActualInvocations:
kafkaTemplate.sendMessage(<any>);
Wanted 1 time:
But was 2
I want kafkaTemplate.sendMessage(); to be called only once but getting called twice after adding ReflectionTestUtils.
Need advice on how to fix this.
You can avoid the usage of ReflectionTestUtils
by slightly refactoring your class and favoring construct injection:
public class MessageProcessor {
private String maxRetry;
private KafkaTemplate template;
// ... any further fields
public class MessageProcessor(@Value("$(invoice.maxRetry)") String maxRetry, KafkaTemplate kafkaTemplate) {
this.maxRetry = maxRetry;
this.kafkaTemplate = kafkaTemplate;
}
}
Within your test you can then control the value of maxRetry
by creating an instance of your class under test (MessageProcessor
) manually.
@ExtendWith(MockitoExtension.class)
public MessageProcessorTest {
@Mock
private KafkaTemplate kafkaTemplate;
private MessageProcessor messageProcessor;
@BeforeEach
void setUp() {
this.messageProcessor = new MessageProcessor("42", kafkaTemplate);
}
}
... and then only rely on JUnit and Mocktio which should help you add the verification.