테스트 환경은 STS에서 spring starter project를 사용했습니다.
- JDK 1.7
- springboot 1.5
- mockito 2.27.0 <- 1.x.x에서 변경함
- https://github.com/royleej9/spring-sample/blob/master/spring-boot-junit/pom.xml
@RunWith(SpringRunner.class)
- junit4 기반으로 테스트 할때 사용합니다.
@ExtendWith(SpringExtension.class)
- junit5 에서 테스트 할때 사용합니다.
@SpringBootTest/ @AutoConfigureMockMvc
- 기본적으로 전체 Bean을 스캔하여 등록하기 때문에 사용하기 제일 쉽지만 전체 빈을 스캔하기 때문에 초기화하는데 시간이 오래 걸릴수 있음
- 실제 서버를 실행하는 것 처럼 테스트 진행 가능
- SpringBootTest 에 @ExtendWith(SpringExtension.class) 선언이 포함되어 있음
기본 설정
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
}
테스트 예제
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TestUserController {
@Autowired
private MockMvc mockMvc;
private static ObjectMapper objectMapper = new ObjectMapper();
final User user1 = User.builder()
.id("id1")
.name("test1")
.password("pwd123")
.createdDate(new Timestamp(System.currentTimeMillis()))
.build();
@Before
public void setup() throws Exception {
String param = objectMapper.writeValueAsString(user1);
this.mockMvc.perform(post("/users")
.contentType(MediaType.APPLICATION_JSON).content(param))
.andExpect(status().isOk())
.andDo(print());
}
@Test
public void testGetUsers() throws Exception {
// when // then
this.mockMvc.perform(get("/users").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andDo(print());
}
...
}
문제점(?)
- @SpringBootTest 사용시 테스트 대상 class를 지정하지 않을 경우 패키지 전체를 스캔하기 때문에 아래와 같은 테스트와 관련이 없는 코드가 자동으로 실행이 됨
- 테스트를 할때마다 타잔 노래가 출력됨...
package royleej9.junit.web.tarzan;
...
@RestController
public class TarzanController {
public TarzanController() {
log.info("INIT TarzanController==============================================================");
final int count = 100000;
for (int i = 0; i < count; i++) {
System.out.println("타잔이" + i * 10 + "원 짜리 팬티를 입고" + i * 20 + "원 짜리 칼을 찾고 노래를 한다.");
}
}
}
@ContextConfiguration / @ComponentScan
- @SpringBootTest의 전체 빈을 스캔하지 않고 테스트에 사용하는 패키지만을 스캔하기 위한 설정
- 테스트 하고자 하는 대상 클래스에서 사용하는 @Component, @Service 등 다른 클래스가 여러 패키지에 속해 있는경우 복잡해지는 문제가 발생
- 예) 테스트 대상 클래스가 royleej9.junit.web.user 패키지에 속해 있지만 다른 클래스(component, service 등...) royleej9.junit.a, royleej9.junit.c, royleej9.junit.d 와 같이 여러 패키지에 속해 있는 경우
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@ContextConfiguration(classes = TestUserConfig.class) // config 클래스 추가
public class TestUserControllerContext {
@Autowired
private MockMvc mockMvc;
...
...
}
@MapperScan("royleej9.junit.web.user")
@AutoConfigureMybatis
@EnableAutoConfiguration
@ComponentScan(basePackages = "royleej9.junit.web.user")// 스캔 범위를 테스트 대상 패키지로 설정
public class TestUserConfig {
}
@SpringBootTest 어노테이션의 classes 속성 사용하기
- 테스트에 필요한 클래스만을 지정하여 테스트 진행
Code: https://github.com/royleej9/spring-sample/blob/master/spring-boot-junit/src/test/java/royleej9/junit/web/user/TestUserControllerClasses.java
@MapperScan("royleej9.junit.web.user") // Mybatis
@AutoConfigureMybatis // Mybatis
@EnableAutoConfiguration
@SpringBootTest(classes= {UserController.class, UserService.class}) // 테스트 대상 클래스 등록
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
public class TestUserControllerClasses {
@Autowired
private MockMvc mockMvc;
...
...
@WebMvcTest
- spring mvc 관련 부분 테스트 할때 사용 ex) Controller url 테스트?
- 테스트 실행 속도는 빠르지만 Mock을 사용해서 메소드 값 등을 설정해야 하기 때문에 테스트 작성 코드가 길어질 수 있음
- @Controller, @ControllerAdvice, @JsonComponent 등 제외한 다른 클래스는 MOCK 을 사용해야함
@WebMvcTest(UserController.class) // 테스트 대상 controller 선언
public class TestUserControllerWebMVC {
// Usercontroller에서 사용하는 service
@MockBean
private UserService userService;
@Autowired
private MockMvc mockMvc;
final User user1 = User.builder()
.id("id1")
.name("test1")
.password("pwd123")
.createdDate(new Timestamp(System.currentTimeMillis()))
.build();
...
@Test
public void testGetUsers() throws Exception {
// getUsers를 사용할때 리턴되는 값을 선언
// given
when(userService.getUsers(null)).thenReturn(Arrays.asList(user1, user2));
// when // then
this.mockMvc.perform(get("/users").contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(2)))
.andDo(print());
}
....
}
참고
'spring' 카테고리의 다른 글
[개발환경] Ubuntu - jdk tar.gz 설치 (0) | 2022.09.23 |
---|---|
[Springboot-junit] - JPA 테스트/@DataJpaTest (0) | 2022.03.06 |
[Spring] properties 설정 분리(2) (0) | 2021.02.17 |
[Spring] properties 설정 분리(1) (0) | 2021.02.17 |
[spring] json 샘플 (0) | 2017.06.27 |