레시피 16-9 스프링 MVC 컨트롤러에 대한 통합 테스트 작성하기

umtuk·2022년 1월 28일
0

스프링 MVC 컨트롤러에 대한 통합 테스트 작성하기

과제

스프링 MVC 프레임워크로 개발한 웹 컨트롤러를 통합 테스트하기

해결책

DispatcherServlet은 스프링 MVC 컨트롤러에 HTTP 요청/응답 객체를 건네줌
MVC 컨트롤러는 비즈니스 처리를 마친 다음 뷰를 렌더링하기 위해 HTTP 요청/응답 객체를 다시 DispatcherServlet에 돌려줌
다른 웹 애플리케이션 프레임워크도 비슷하지만 HTTP 요청/응답 객체를 시뮬레이션하고 목 환경을 설정하는 일이 스프링 MVC 컨트롤러의 통합 테스트에서 가장 까다로운 부분
스프링은 목 MVC 테스트를 지원하므로 목 서블릿 환경을 쉽게 구성 가능

스프링 테스트 목 MVC를 이용해 WebApplicationContext를 구성하면 목 MVC API를 이용해 HTTP 요청을 시뮬레이션하고 그 결과를 확인 가능

풀이

웹 관련 빈들을 구성클래스에 설정

@Configuration
@EnableWebMvc
@ComponentScan(value = "com.apress.springrecipes.bank.web")
public class BankConfiguration {

    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }
}

@EnableWebMvc를 적용해 애너테이션 기반의 컨트롤러를 활성화
@ComponentScan으로 @Controller 빈을 자동 등록
InternalResourceViewResolver가 뷰 이름을 URL로 바꿔주면 브라우저는 해당 페이지를 렌더링

통합 테스트, BankConfiguration 클래스에 설정한 내용을 로드하고 클래스 레벨에 @WebAppConfiguration을 붙여 일반 ApplicationContext가 아닌 WebApplicationContext를 가져오도록 테스트 컨텍스트 프레임워크에 알림

JUnit 에서 스프링 MVC 컨트롤러 통합 테스트하기

테스트가 끝나면 등록했던 테스트 데이터를 롤백해야 하므로 AbstractTransactionalJUnit4SpringContextTests를 상속하는 게 가장 간편

@ContextConfiguration(classes = BankConfiguration.class)
public class AccountServiceJUnit4ContextTests extends AbstractTransactionalJUnit4SpringContextTests {

    private static final String ACCOUNT_PARAM = "accountNo";
    private static final String AMOUNT_PARAM = "amount";

    private static final String TEST_ACCOUNT_NO = "1234"
    private static final String TEST_AMOUNT = "50.0";

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc = mockMvc;

    @Before
    public void init() {
        executeSqlScript("classpath:/bank.sql", true);
        jdbcTemplate.update(
                "INSERT INTO ACCOUNT (ACCOUNT_NO, BALANCE) VALUES (?, ?)",
                TEST_ACCOUNT_NO, 100);
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).bulid();
    }

    @Test
    public void deposit() throws Exception {
        mockMvc.perform(
            get("/deposit.do")
                .param(ACCOUNT_PARAM, TEST_ACCOUNT_NO)
                .param(AMOUNT_PARAM, TEST_AMOUNT)
            .andDo(print())
            .andExpect(forwardedUrl("/WEB-INF/views/success.jsp"))
            .andExpect(status().isOK());
        )
    }
}

MockMvc 객체는 init() 메서드에서 간편히 MockMvcBuilders로 생성
팩토리 메서드 webAppContextSetup()를 호출해 이미 불러들인 WebApplicationContextMockMvc 객체를 초기화
MockMvc 객체는 스프링 MVC 애플리케이션의 DispatcherServlet을 흉내내서 WebApplicationContext로 핸들러 매핑 및 뷰 해석 전략을 설정하고 인터셉터가 구성되어 있으면 모두 찾아내 적용

테스트할 계정은 init() 메서드에서 SQL문으로 미리 설정

deposit() 테스트 메서드는 앞서 초기화한 MockMvc 객체를 이용해 매개변수가 2개(accountNo, ammount)GET/deposit.do 요청이 들어오는 장면을 시뮬레이션
MockMvcRequestsBuilders.get() 팩토리 메서드가 반환한 RequestsBuilder 인스턴스는 mockMvc.perform() 메서드의 인수로 전달

perform() 메서드가 ResultActions 객체를 반환하면 그 결과에 대해 어떤 액션을 취하거나 어설션을 수행 가능
andDo(print()) 메서드는 테스트 코드를 디버깅할 때 요긴한 요청과 응답 정보를 출력
어설션 2개로 작동 여부를 확인
DepositController가 success를 viewname으로 반환하면 ViewResolver 설정에 따라 /WEB-INF/views/success.jsp로 포워딩
status().isOK()는 반환코드가 200(OK)인지 확인

TestNG에서 스프링 MVC 컨트롤러 통합 테스트하기

TestNG에서는 AbstractTransactionalTestNGSpringContextTests를 상속 후 @WebAppConfiguration을 붙여 스프링 목 MVC를 사용

@ContextConfiguration(classes = BankConfiguration.class)
@WebAppConfiguration
public class AccountServiceJUnit4ContextTests extends AbstractTransactionalTestNGSpringContextTests {

    @BeforeMethod
    public void init() {
        executeSqlScript("classpath:/bank.sql", true);
        jdbcTemplate.update(
                "INSERT INTO ACCOUNT (ACCOUNT_NO, BALANCE) VALUES (?, ?)",
                TEST_ACCOUNT_NO, 100);
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).bulid();
    }
profile
https://github.com/umtuk

0개의 댓글