Affects: current, see https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html


I am trying to get my mock to return a custom exception for every method call. This should be fairly easy by passing it a custom answer implementation which implements Answer<Object> and overrides public Object answer(InvocationOnMock invocation) throws Throwable.

For example consider this example modeled after org.mockito.Answers (which is referenced in the API doc):

package com.foo.utils;

import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public enum ExceptionAnswers implements Answer<Object> {
  RUNTIME_EXCEPTION(new RuntimeExceptionAnswer());


  private final Answer<Object> implementation;

  ExceptionAnswers(Answer<Object> implementation) {
    this.implementation = implementation;
  }

  @Override
  public Object answer(InvocationOnMock invocation) throws Throwable {
    return implementation.answer(invocation);
  }

  public static class RuntimeExceptionAnswer implements Answer<Object> {
    public Object answer( InvocationOnMock invocation ) {
      throw new RuntimeException ( invocation.getMethod().getName() + " threw RuntimeException" );
    }
  }
}

and its usage as for example

package com.allianz.cee.sme.controller;

import com.foo.service.CompanyService;
import com.foo.utils.ExceptionAnswers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;

@SpringBootTest
@AutoConfigureMockMvc
class CompanyControllerTest {

  @Autowired
  MockMvc mockMvc;

  @MockBean(answer = ExceptionAnswers.RUNTIME_EXCEPTION)
  CompanyService mockService;

  @Test
  void doSomething(){...}
}

However, this will give me the following error: Incompatible types. Found: 'com.foo.utils.ExceptionAnswers', required: 'org.mockito.Answers'

This hard dependency on the mockito.Answers enum prevents any extension and customization as an enum can not be extended.

Now the great thing is that mockito.Answers already implements Answer<Object> so all that needs to be done is to change the type of @MockBean's answer field.

Please let me know if you need more information.

Cheers!

Comment From: jnizet

That wouldn't be valid Java code.

An annotation type element can only be a primitive type, a String, a Class, an enum type, an annotation type or an array type whose component type is one of the preceding types.

See https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.6.1.

Comment From: snicoll

That and MockBean is part of Spring Boot so there's nothing actionable here.