Search code examples
javaspringmockitointegration-testingspring-rabbit

Mockito doAnswer()


Can I somehow use doAnswer() when an exception is thrown?

I'm using this in my integration test to get method invocations and the test in configured the @RabbitListenerTest...

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyIT {

@Autowired
private RabbitTemplate rabbitTemplate;

@Autowired
private MyRabbitListener myRabbitListener;

@Autowired
private RabbitListenerTestHarness harness;

@Test
public void testListener() throws InterruptedException {
  MyRabbitListener myRabbitListener = this.harness.getSpy("event");
  assertNotNull(myRabbitListener);

  final String message = "Test Message";
  LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(1);
  doAnswer(answer).when(myRabbitListener).event(message);

  rabbitTemplate.convertAndSend("exchange", "key", message);

  assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
  verify(myRabbitListener).messageReceiver(message);
}

@Configuration
@RabbitListenerTest
public static class Config {
  @Bean
  public MyRabbitListener myRabbitListener(){
    return new MyRabbitListener();
  }
 }
}

It works ok but when I introduce an Exception being thrown, It doesn't i.e

This works

@RabbitListener(id = "event", queues = "queue-name")
  public void event(String message) {
    log.info("received message > " + message);
}

This doesn't

@RabbitListener(id = "event", queues = "queue-name")
  public void event(String message) {
    log.info("received message > " + message);
    throw new ImmediateAcknowledgeAmqpException("Invalid message, " + message);
}

Any help appreciated


Solution

  • The LatchCountDownAndCallRealMethodAnswer is very basic

    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        invocation.callRealMethod();
        this.latch.countDown();
        return null;
    }
    

    You can copy it to a new class and change it to something like

    private volatile Exception exeption;
    
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        try {
            invocation.callRealMethod();
        } 
        catch (RuntimeException e) {
            this.exception = e;
            throw e;
        }
        finally {
            this.latch.countDown();
        }
        return null;
    }
    
    public Exception getException() {
        return this.exception;
    }
    

    then

    assertTrue(answer.getLatch().await(20, TimeUnit.SECONDS));
    assertThat(answer.getException(), isInstanceOf(ImmediateAcknowledgeAmqpException.class));
    

    Please open a github issue; the framework should support this out-of-the-box.