befocused47
befocused47

Reputation: 44

Springboot & Mockito - Using ReflectionTestUtils.setField calling method twice

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.

Upvotes: 1

Views: 1477

Answers (1)

rieckpil
rieckpil

Reputation: 12021

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.

Upvotes: 0

Related Questions