N-LAB

JUnit 5 × Java 21で@ExceptionHandlerのユニットテストを実装する

投稿日: 2024年7月28日


目標


条件


テストコードの実装

ErrorController:テスト対象のコントローラ(hasErrorがtrueの場合にExceptionをスローする)

@Controller
public class ErrorController {
  @GetMapping(value = "test")
  public String hoge(@RequestParam(name = "hasError") boolean hasError, Model model) throws Exception {
    if (hasError) throw new Exception("An unexpected error has occurred.");
    model.addAttribute("status", "OK");
    return "test";
  }
}

ErrorHandlerController:Exceptionをキャッチするコントローラ(Exceptionをキャッチした場合にerror.htmlを表示する)

@ControllerAdvice
public class ErrorHandlerController { 
  @ExceptionHandler({Exception.class})
  public String handleException(Exception e) {
    return "error";
  }
}


1. ErrorControllerTest.javaを新規作成し、以下の内容を実装します

package sample.application.controller;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

@ExtendWith(SpringExtension.class)
@ExtendWith(MockitoExtension.class)
@SpringBootTest
@TestExecutionListeners({
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
})
public class ErrorControllerTest {
  @InjectMocks()
  ErrorController errorController;
  private MockMvc mockMvc;

  @BeforeEach
  public void setUp() {
    mockMvc = MockMvcBuilders.standaloneSetup(errorController)
        .setControllerAdvice(new ErrorHandlerController())
        .build();
  }

  @Test
  @DisplayName("Exceptionがスローされ、exception handlerにキャッチされてerror.htmlが表示されること")
  public void hasErrorTrue() throws Exception {
    // Assert
    mockMvc.perform(get("/test").param("hasError", "true"))
        .andExpect(status().isOk())
         // エラーオブジェクトの検証
        .andExpect(result -> assertInstanceOf(Exception.class, result.getResolvedException()))
         // エラーメッセージの検証
        .andExpect(result -> assertEquals("An unexpected error has occurred.", result.getResolvedException().getMessage()))
         // 表示されるhtml(view)の検証
        .andExpect(view().name("error"));
  }

  @Test
  @DisplayName("Exceptionがスローされず、test.htmlが表示されること")
  public void hasErrorFalse() throws Exception {
    // Assert
    mockMvc.perform(get("/test").param("hasError", "false"))
        .andExpect(status().isOk())
        .andExpect(model().hasNoErrors())
         // modelにセットされた値の検証
        .andExpect(model().attribute("status", "OK"))
         // 表示されるhtml(view)の検証
        .andExpect(view().name("test"));
  }
}




DependencyInjectionTestExecutionListener.class
DirtiesContextTestExecutionListener.class


以上で全ての手順は完了になります