Не отрабатывает @ControllerAdvice в юнит тестах

217
06 июля 2018, 22:10

Есть контроллер:

@RestController
@RequestMapping("/api/entity")
public class EntityController {
    @Autowired
    EntityService entityService;
    @PostMapping
    public Entity saveEntity(@RequestBody @Valid Entity entity){
        return entityService.save(entity);
    }
}

Есть перехватчик ошибок:

@ControllerAdvice
public class ExceptionsHandler extends ResponseEntityExceptionHandler {
    private static final Logger LOGGER = Logger.getLogger(ExceptionsHandler.class.getName());
    @Autowired
    MessagesUtil messagesUtil;
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleConflict(MethodArgumentNotValidException ex, HttpHeaders headers, WebRequest request) {
        LOGGER.warning(messagesUtil.message("test.basicexception", new Object[]{HttpStatus.CONFLICT.value()}));
        List<String> errors = new ArrayList<>();
        ex.getBindingResult().getFieldErrors().forEach(e -> errors.add(e.getField() + ": " + e.getDefaultMessage()));
        ex.getBindingResult().getGlobalErrors().forEach(e -> errors.add(e.getObjectName() + ": " + e.getDefaultMessage()));
        errors.forEach(error -> headers.add("errorMessage", error));
        headers.add("error", String.valueOf(HttpStatus.CONFLICT.value()));
        return handleExceptionInternal(ex, null, headers, HttpStatus.CONFLICT, request);
    }
}

Есть юнит тест:

@WebMvcTest(controllers = EntityController.class, secure = false)
@RunWith(SpringRunner.class)
public class EntityControllerTest {
    @MockBean
    EntityService entityService;
    @Autowired
    private MockMvc mvc;
    private final static Long ID_1 = 1L;
    private final static Long ID_2 = 2L;
    private final static Long ID_3 = 3L;
    private final static String ENTITY_1 = "entity 1";
    private final static String ENTITY_2 = "entity 2";
    private final static String ENTITY_3 = "entity 3";
    private final static String UPDATED_ENTITY = "entity 4";
    @Before
    public void setup(){
        Entity entity1 = new Entity(ID_1, ENTITY_1);
        failEntity = new Entity(ID_1, ENTITY_1);
        when(entityService.findAll()).thenReturn(Arrays.asList(entity1, new Entity(ID_2, ENTITY_2),
                new Entity(ID_3, ENTITY_3)));
        when(entityService.findOne(ID_1)).thenReturn(entity1);
    }
    @Test
    public void saveEntity_conflict() throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(EntityController.class)
                .setControllerAdvice(new ExceptionsHandler())
                .build();
        mvc.perform(post("/api/entity")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isConflict());
    }
}

Тест валится на ассерте со следующим сообщением:

java.lang.AssertionError: Status Expected :409 Actual :404

Запустил проект, дернул этот метод и мне вернулась 409 ошибка. Похоже, что проблема именно в тестах. Как можно поправить тест?

Answer 1

Так как @WebMvcTest подготавливает только контроллер к тесту и не делает @ComponentScan, вам нужно самому подключить @ControllerAdvice через компонент скан.

@WebMvcTest(controllers = EntityController.class, secure = false)
@RunWith(SpringRunner.class)
public class EntityControllerTest {
    @MockBean
    EntityService entityService;
    @Autowired
    private MockMvc mvc;
    private final static Long ID_1 = 1L;
    private final static Long ID_2 = 2L;
    private final static Long ID_3 = 3L;
    private final static String ENTITY_1 = "entity 1";
    private final static String ENTITY_2 = "entity 2";
    private final static String ENTITY_3 = "entity 3";
    private final static String UPDATED_ENTITY = "entity 4";
    @Before
    public void setup(){
        Entity entity1 = new Entity(ID_1, ENTITY_1);
        failEntity = new Entity(ID_1, ENTITY_1);
        when(entityService.findAll()).thenReturn(Arrays.asList(entity1, new Entity(ID_2, ENTITY_2),
                new Entity(ID_3, ENTITY_3)));
        when(entityService.findOne(ID_1)).thenReturn(entity1);
    }
    @Test
    public void saveEntity_conflict() throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(EntityController.class)
                .setControllerAdvice(new ExceptionsHandler())
                .build();
        mvc.perform(post("/api/entity")
                .contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isConflict());
    }
    @Configuration
    @ComponentScan(...)
    public static class TestMvcConfig {
    }
}

Можно еще использовать @SpringBootTest и @AutoConfigureMockMvc вместо @WebMvcTest, тогда спринг сам сделает скан и настроит ваш контроллер для теста.

READ ALSO
Cannot resolve symbol Theme из-за gradle

Cannot resolve symbol Theme из-за gradle

Когда добавляю classpath в первый файл buildgradle

204
Java. Сборка war gradle

Java. Сборка war gradle

Начал изучать систему сборки gradleНаписал приложение с использованием websocket(Sockjs)

224
Библиотека json simple. JSONArray to List&lt;String&gt;. Stream API

Библиотека json simple. JSONArray to List<String>. Stream API

У меня есть json строка, которая представляется собой массив

184
Собрать видеоряд из изображений Java

Собрать видеоряд из изображений Java

Средствами opencv я разбил видео на изображения(png), а теперь хочу собрать обратно(включая аудиоряд), но не знаю как

187