MockMvc로 컨트롤러 테스트하기

HiroPark·2022년 12월 16일
0

Spring

목록 보기
11/11
@RequiredArgsConstructor
@Controller
public class AlertController {

    private final AlertService alertService;
.
.
@GetMapping("/alerts")
    public String findAlert(Model model) {

        List<alertResponseDto> alerts = alertService.findByUser(model);

        ArrayList<String> tickers = alertService.findAllTickers(model);

        if (alerts != null) {
            model.addAttribute("alerts", alerts);
        }

        model.addAttribute("tickers", tickers);

        return "alert";
    }
.
.

View를 리턴하는 단순한 컨트롤러 메서드를 테스트하려 합니다.

제가 아는 스프링 테스트 방법은 TestRestTemplate을 사용하는 것과 MockMvc를 사용하는 것 두가지가 있는데요.

전체 프레임워크를 사용하지 않고 엔드포인트에 바로 Http Request를 날려서 테스트를 진행하는 TestRestTemplate를 사용하지 않고, MockMvc를 사용하기로 했습니다.

MockMvc는 Mvc의 컨트롤러를 테스트하는데 특화돼있습니다. Http requset를 모방하여 전체 스프링 context안에서 Controller를 테스트할 수 있습니다. 따라서 Controller를 실제 어플리케이션 환경처럼 model과 viewResolver등 다른 컴포넌트들과의 상호작용 속에서 테스트 할 수 있습니다.

@ExtendWith(SpringExtension.class) // Junit5 : @Test 애노테이션을 junit.jupiter.api.Test 로 사용중
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureMockMvc
public class AlertControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private AlertController alertController;

    @Autowired
    private UserRepository userRepository;
    
    @Before
    public void setup() {
        ViewResolver viewResolver = new MustacheViewResolver();

        mockMvc = MockMvcBuilders.standaloneSetup(alertController)
                .setViewResolvers(viewResolver)
                .build();
    }

    @AfterEach
    public void tearDown() {
        userRepository.deleteAll();
    }

    @Test
    @WithMockCustomUser
    @Sql(statements = "INSERT INTO user (name, email, role)\n" +
            "VALUES ('testName', 'testEmail@naver.com', 'USER');")
    public void AlertPage_loading_test() throws Exception {
        String body = mockMvc.perform(get("/alerts"))
                .andExpect(status().isOk())
                .andDo(print())
                .andReturn()
                .getResponse()
                .getContentAsString();

        // then
        Assertions.assertThat(body).contains("알림 등록");
    }
.
.

테스트 코드입니다.

@Test애노테이션을 Junit5를 사용하고 있기 때문에
@ExtendWith(SpringExtension.class)를 사용해주었습니다.
@RunWith(SpringRunner.class)을 사용할시 Initialization error가 발생합니다.

  • 현재 DB에 User가 없기에 user를 넣어줘야만 NPE를 피할 수 있습니다. @Sql 애노테이션을 이용하여 DB에

MockMvcBuilder를 통해 mockMvc객체를 생성해줍니다. 이때 standaloneSetup은 mockMvc 객체가 테스트하고자 하는 controller를 인자로 받습니다. 이는 하나의 컨트롤러를 테스트하기 위한 뼈대가 됩니다.

더불어서, setViewResolvers를 통해 mockMvc에 ViewResolver를 구성합니다. ViewResolver란 view 이름을 실제 view object와 연결하는 역할을 하는 인터페이스입니다. 머스태치를 사용하고 있기에 MustacheViewResolver를 만들어 넣어줍니다.

@AutoConfigureMockMvc 는 mockMvc 객체가 자동으로 configuration을 하는 것을 돕습니다. 이를 통해 @Autowired된 필드와 mockMvc를 통합합니다.
이 애노테이션은 @SpringBootTest 애노테이션과 함께 사용되는데, 이를 통해 수동적으로 configuration할 필요 없이 MockMvc 객체를 만들 수 있습니다.


추가
실제 애플리케이션 DB와 테스트용 DB가 같다보니, local을 구동중인 상태에서는 User 객체가 DB에 존재해서 테스트가 통과하지만, 서버를 끄면 테스트가 실패하는 불상사가 발생했습니다.

따라서 이참에 테스트 데이터베이스를 H2로 분리하였습니다.

h2 db를 미리 생성해놓고,

build.gradle에 추가

    runtimeOnly 'com.h2database:h2' // 테스트 코드 작성시 사용할 DB(H2)

test/resources/application.properties 변경

spring.datasource.test.url=jdbc:h2:mem:testdb
spring.datasource.test.driverClassName=org.h2.Driver
spring.datasource.test.username=sa
spring.datasource.test.password=password

spring.profiles.include=oauth
spring.session.store-type=jdbc
spring.session.jdbc.initialize-schema=always
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update

spring.security.oauth2.client.registration.google.client-id=test
spring.security.oauth2.client.registration.google.client-secret=test
spring.security.oauth2.client.registration.google.scope=test

이렇게 데이터베이스를 분리해주니 마음이 한결 편해졌습니다

profile
https://de-vlog.tistory.com/ 이사중입니다

0개의 댓글