- SpringTestSupport 클래스에 설정 후 이 클래스를 상속받아 테스트를 개발함.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RootContextConfig.class },
loader = AnnotationConfigWebContextLoader.class)
@WebAppConfiguration
public class SpringTestSupport {
@Autowired
protected WebApplicationContext wac;
protected MockMvc mockMvc;
@Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
@Test
public void isWebAppContextLoadingProperly() {
ServletContext servletContext = wac.getServletContext();
Assert.assertNotNull(servletContext);
Assert.assertTrue(servletContext instanceof MockServletContext);
Assert.assertNotNull(wac.getBean("rootContextConfig"));
}
}@RunWith(SpringJUnit4ClassRunner.class)
- 이 애노테이션을 붙여줘야 스프링 테스트를 Junit으로 돌릴 수 있음.
@ContextConfiguration(classes = { RootContextConfig.class }, loader = AnnotationConfigWebContextLoader.class)
- RootContextConfig.class를 spring context의 빈 설정 파일로 사용한다는 의미.
@WebAppConfiguration
- 이 애너테이션을 붙이면 Controller및 web환경에 사용되는 빈들을 자동으로 생성하여 등록하게됨.
참고
- DB 프로퍼티 파일은 src/test/resource경로가 classpath로 잡히기 때문에 이 경로에 db.properties파일이 있어야 함.(dp.properties파일 이름은 src/main/resource 경로에 있는 파일명과 동일하게 지었음. 따로 테스트전용 리소스 파일을 관리하지않고 h2database만 설정하기 위함)
public class UserControllerTest extends SpringTestSupport {
@Test
public void issueTokenApiTest() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.get("/v1/issue-token"))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().is(HttpStatus.OK.value()))
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andReturn();
Assert.assertEquals(MediaType.APPLICATION_JSON_UTF8_VALUE,
mvcResult.getResponse()
.getContentType());
Assert.assertEquals(HttpStatus.OK.value(),
mvcResult.getResponse()
.getStatus());
}
}- spring integration test 참고 : https://www.baeldung.com/integration-testing-in-spring
h2database 설정 파일
# db connect setting
datasource.driverClassName=org.h2.Driver
datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1;
datasource.username=codingsquid
datasource.password=1234- Controller를 테스트 할 경우 Service layer까지 내려가게됨. Controller만 테스트하고 싶다면 Service를 Mocking하면 됨.
- mocktio framework을 이용하여 적용해보자.
import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
위와같은 import static을 통해 static method를 사용하게 하였다.
public class UserControllerTest extends SpringTestSupport {
@Mock
private UserService userService;
@InjectMocks
private UserController userController;
@Test
public void issueTokenApiIntegrateTest() throws Exception {
this.mockMvc.perform(get("/v1/issue-token"))
.andDo(print())
.andExpect(status().is(HttpStatus.OK.value()))
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(jsonPath("$.result.token").exists())
.andExpect(jsonPath("$.result.created_at").exists());
}
@Test
public void issueTokenApiUnitTest() {
MockitoAnnotations.initMocks(this);
LocalDateTime testTime = LocalDateTime.now();
givenUserService(testTime);
ApiResponseModel<AccessToken> result = userController.issueToken();
Assert.assertEquals(result.getCode(), HttpStatus.OK.value());
Assert.assertEquals(result.getMsg(), HttpStatus.OK.getReasonPhrase());
Assert.assertEquals(result.getResult().getToken(), "this is sample access-token");
Assert.assertEquals(result.getResult().getCreatedAt(), testTime);
}
private void givenUserService(LocalDateTime createdAt) {
User mockUser = new User();
mockUser.setAccessToken(new AccessToken("this is sample access-token", createdAt));
when(userService.registerUser()).thenReturn(mockUser);
}
}- Mocking전의 테스트 코드와 비교하여 달라진 점은 @Mock, @InjectMocks와 givenUserService 메서드가 추가돼고 MockitoAnnotations.initMocks(this); 줄이 포함됨. 하나씩 알아가 보자.
- @Mock -> Mocking할 빈을 설정 한다.
- @InjectMocks -> UserController빈을 Context에 등록할 때 연관관계를 가진 빈 대신 Mocking된 빈을 집어 넣는다.
- givenUserService에서 when 메서드에 userService의 registerUser()메서드가 호출되면 mockUser를 return하게 만든다.
- given, when, then 패턴을 알아두자.
- MockitoAnnotations.initMocks(this); -> 현재 테스트 클래스의 @Mock이 달린 객체를 초기화하는 작업이다. 첨언하자면 테스트 클래스는 @Test가 붙은 메서드마다 객체가 새로 만들어지게 되며 issueTokenApiUnitTest메서드가 호출될 때 새로 생성된 테스트 클래스의 객체를 파라미터로 넣어준다.