- Fast : 빨라야 한다.
- Independent: 독립적이어야 한다.
- Repeatable: 반복 가능해야한다.
- Self-validating: 자체적으로 테스트 결과가 도출되야한다. (개발자가 print 찍어서 비교하는게 아니고 자동으로 수행되며 성공/실패 의 결과가 나오는 것)
- Timely: 단위 테스트는 실제 코드보다 먼저 구현해야한다. (TDD일 경우에만 해당)
- Given: 테스트에 필요한 및 Mock 객체를 통해 특정 상황에 대한 행동을 정의
- When: 실제 테스트를 하는 메소드가 호출되며 테스트를 통한 결과값을 가져옴
- Then: When 단계에서 나온 결과값을 검증
- JUnit : Java 에서 사용되는 대표적인 테스트 프레임워크. 자바 개발자 93% 가 사용한다는 통계가 있습니다.
- Mockito: Mock(가짜) 객체를 쉽게 만들고, 관리하고, 검증할 수 있는 방법을 제공하는 프레임워크. Mock 객체는 진짜 객체와 비슷하게 동작하지만 프로그래머가 직접 행동을 관리하는 객체
- @Mock: Mock 객체를 만들어 반환해주는 어노테이션
- @Spy: 원본 메소드 그대로 사용하는 어노테이션
- @InjectMocks: @Mock 또는 @Spy로 생성된 가짜 객체를 자동으로 주입시켜주는 어노테이션
@Mock // 가짜 개체로 만들 것
private UserRepository userRepository;
@InjectMocks // 주입되는 곳 지정
private UserService userService;
@BeforeEach // 테스트 마다 직전에 한 번씩 반복되는 메소드
void prepare() {
ReflectionTestUtils.setField(jwtUtil,
"secretKey", // jwtUtil의 secretKey값이 저장될 변수
"7ZWt7ZW0OTntmZTsnbTtjIXtlZzqta3snYTrhIjrqLjshLjqs4TroZzrgpjslYTqsIDsnpDtm4zrpa3tlZzqsJzrsJzsnpDrpbzrp4zrk6TslrTqsIDsnpA="); // secretKey의 값
jwtUtil.init(); // jwtUtil에서 @PostConstructor가 동작하지 않기 때문에, 임의로 실행시켜야 함
}
@Spy // 원본 그대로 사용하기 원하는 개체
private JwtUtil jwtUtil;
- @BeforeAll: 테스트를 시작하기 전에 호출되는 메서드
- @BeforeEach: 각 테스트 메서드가 실행되기 전에 동작하는 메서드
- @AfterAll: 테스트를 종료하면서 호출되는 메서드
- @AfterEach: 각 테스트 메서드가 종료되면서 호출되는 메서드
@Test
@DisplayName("회원 가입")
void signup() {
// given
SignupRequest request = SignupRequest.builder()
.admin(false)
.username("nathan")
.password("1234qwer")
.email("nathan@gmail.com")
.build();
when(userRepository.findByUsername(any(String.class)))
.thenReturn(Optional.empty()); // repository에서 받아올 값 지정
// when
ResponseStatusDto response = userService.signup(request);
// then
// 코드 확인
assertThat(response.getStatusCode()).isEqualTo(StatusEnum.SIGN_SUCCESS.getStatusCode());
// 메시지 확인
assertThat(response.getMsg()).isEqualTo(StatusEnum.SIGN_SUCCESS.getMsg());
}
mockMvc를 활용해 Controller가 Mvc에서 데이터를 받아오는 것처럼 테스트 가능
@BeforeEach // 테스트 이전에 한 번씩 진행
public void init() { // mockMvc를 적용
mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
}
@Test
@DisplayName("회원가입 (성공)")
void signup() throws Exception {
// given
SignupRequest request = SignupRequest.builder()
.admin(false)
.username("nathan")
.password("1234qwer")
.email("nathan@gmail.com")
.build();
ResponseStatusDto response = new ResponseStatusDto(StatusEnum.SIGN_SUCCESS);
when(userService.signup(any(SignupRequest.class)))
.thenReturn(response);
// when
//API를 기준으로 테스트
ResultActions resultActions = mockMvc.perform(
MockMvcRequestBuilders.post("/api/users/signup")
.contentType(MediaType.APPLICATION_JSON)
.content(new Gson().toJson(request))); //Json 형식으로 변형
// then
resultActions.andExpect(status().isOk())
.andExpect(jsonPath("statusCode", response.getStatusCode()).exists())
.andExpect(jsonPath("msg", response.getMsg()).exists());
}
@Autowired // 연결만 하고 사용
private UserRepository userRepository; // repository는 DB에 다녀와야 한다.
@Test
@DisplayName("사용자 추가")
void addUser() {
// given
User user = new User(
"nathan",
"1234qwer",
"nathan@gmail.com",
UserRoleEnum.USER
);
// when
User saveUser = userRepository.save(user);
// then
assertThat(saveUser.getUsername()).isEqualTo(user.getUsername());
}
gson 사용하기 위해서 아래 의존성에 추가 -> json형식으로 바꿀 수 있게 도와줌
testImplementation 'com.googles.code.gson:2.9.0'