Mockito
- 개발자가 동작을 직접 설정하는 방식으로 가짜 객체를 만들어주는 테스트 프레임 워크
- 가짜 객체를 만들어 Spring내 객체간의 의존성 없이 테스팅이 가능하게 만들어준다.
- 가짜 객체로 시뮬레이션(Stub)하여 단위 테스트를 진행하는 원리
관련 애너테이션
- @Mock : 가짜 객체를 만들어 줌.
- @Spy : 시뮬레이션을 만들지 않은 메서드 사용시 해당 클래스의 실제 메서드를 그대로 사용하게 해줌
- @InjectMocks : @Mock, @Spy 둘 중 하나로 생성된 가짜 객체를 자동 주입.
JUNIT5 + Mockto
- 둘을 같이 쓰기 위해서는 결합이 필요하다.
- 아래 내용을 클래스 상단에 작성
@ExtendWith(MockitoExtension.class)
Mock객체에 필요한 필드 추가
- 간단한 변수들은 메서드를 만들어 삽입시킨다.
- 다른 객체들은 @Mock 처리시 삽입 가능하다.
(+) @WebMvcTest
추가적으로 다른 방법으로는 @WebMvcTest를 사용하는 방법도 존재한다.
이는 실제 컨트롤러 빈을 불러와 사용하는 방식이다.
@SpringBootTest와의 차이점은 SpringBootTest 애너테이션은 실제 모든 빈을 불러와 실제 환경과 동일하게 테스팅함을 의미하지만
@WebMvcTest는 설정한 컨트롤러 빈만 불러온다.
하지만 Spring Security Config 또한 불러오지 않기 때문에 Spring Test 시에 기본 Spring Security가 설정된다. 즉, Config에서 인증/인가 설정한 것이 적용되지 않는다. 따라서 csrf나 권한부여등을 테스트에서 따로 해주어야 한다.
- .with(csrf()) 사용
- @WithMockUser, @WithUserDetails, @WithAnonymousUser, with(user()) 등 사용해서 권한 부여
UNIT TEST의 과정 (BDD 채택)
1. given : 해당 메서드가 특정 값을 반환할 것임을 개발자가 설정
- 예시
- doReturn : 이러한 결과를 반한하게 설정할 것이다.
- when : 이러한 상황이 주어졌을 때
// given
MemberDTO sample = MemberDTO.sample();
String response = "success";
doReturn(response).when(memberServiceImpl).registerMember(any(MemberDTO.class));
(+)
doNothing() : 아무것도 안할 것이다.
doThrow() : 예외를 발생기킬것이다.
(+) 반환 클래스의 입력시 any 사용
any(클래스명.class)
anyString()
anyInt()
(+) QueryFactory
- 순서대로 반환결과를 모두 Mocking 해주어야한다.
- 또한, FetchFirst()와 같은 메서드는 원래 두개의 메서드로 이루어져있다 limit+fetchOne. 따라서 둘다 반환을 정해주어야 한다.
예시
Integer exist_id = queryFactory.selectOne().from(memberEntity)
.where(memberEntity.userId.eq(user_id)).fetchFirst();
doReturn(jpaQuery).when(queryFactory).selectOne();
doReturn(jpaQuery).when(jpaQuery).from(memberEntity);
doReturn(jpaQuery).when(jpaQuery).where(memberEntity.userId.eq(userId));
doReturn(jpaQuery).when(jpaQuery).limit(1);
doReturn(entity).when(jpaQuery).fetchOne();
2. when : 상황을 부여
MockMvc
예시1 : Http 요청에 대한 Controller의 응답을 확인하는 경우
- ResultActions.class : 해당 동작에 대한 결과를 담는 클래스
- MockMvc.class : Spring에서 제공하는 HTTP 테스트 클래스
- .perform : 결과로는 ResultActions 클래스를 받으며, 요청을 전송하는 역할을 수행
- .post(), .get(), .put(), .delete() : HTTP 메서드를 의미
- .contentType : JSON 등 타입을 설정 가능
- .content : Body에 데이터를 담을 수 있다. 직접작성시 아래와 같이 작성
- .with() : 무언가 같이 붙여 전송가능 예를들어, csrf, user 등
- .param, .params : 파라미터 한개 또는 여러개 전송 가능, MultiValueMap클래스를 전달
예시 : .param("key", "value") -> int는 String으로 변환해 작성(1 -> "1")
"{\"userPwd\": \"userPwd\"}";
private MockMvc mockMvc;
// 해당 부분은 가짜 객체에 필요한 부분을 미리 세팅하는 것이 좋다.
@BeforeEach
public void init() {
mockMvc = MockMvcBuilders.standaloneSetup(memberController).build();
}
// when
ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.post("/member")
.contentType(MediaType.APPLICATION_JSON).content(new Gson().toJson(sample)));
(+) params 예시
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
// 이 후, put메서드를 통해 String과 List<String>을 넣어준다.
3. then : 예상한 결과에 부합하는지 확인
- 예시 : 응답 결과 예상 및 결과 출력
- andExpect : status(), view(), redirect(), model(), content() 등 사용 가능
- andDo() : 결과 출력
- assertThat : 결과값 확인
- assertThrows(Exception클래스, () -> {클래스.메서드}) : 오류 처리
- assertEquals(String, String) : 둘의 내용이 같은지 확인
// then
resultActions.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().string(equalTo(response))).andDo(print());
// json 값 확인
.andExpect(jsonPath("$.store1").value(1));
(+) 타입별 비교
// 1. String
assertEquals("A", "A");
// 2. Integer
assertThat(1, is(1));
// 3. Long
assertThat(1L, equalTo(1L));
// Null 체크
assertThat(1, is(nullValue()));
// 둘의 import가 다름
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
4. verify : 받은 데이터 검증 과정
- 예시 : 가짜 객체로 만든 클래스의 메서드의 호출횟수 검증
// 해당 메서드가 한번 호출 되었는지
verify(memberDAOImpl, times(1)).registerMember(any(MemberEntity.class));
// 메서드가 조건에 맞는 인자로 호출되는지 검증
verify(storeListCache).save(argThat(storeListDTO ->
storeListDTO.getAddress().equals(address) &&
storeListDTO.getStoreList().equals(mockStoreList)));
verify(storeDAO).getStoreList(eq(country), eq(city), eq(dong), eq(type), eq(page), eq(size));
(+) DataBase Test
데이터 베이스를 테스트 하기 위한 기본적인 베이스는 아래와 같다.
1. 실제 데이터 베이스 연결 (H2등의 인메모리 또는 실제 사용하는 DB)
2. 필요한 Config 주입
- 기본적으로 @DataJpaTest는 인메모리 데이터베이스인 H2를 활용해 데이터를 테스팅한다. 이때 자동으로 롤백해주어 데이터 저장 및 삭제에 대해서 롤백처리를 해준다.
- @AutoConfigureTestDatebase는 자신이 사용하는 데이터 베이스를 사용할것인지 또는 설정을 추가할 것인지에 대해 설정을 해줄 수 있다. 아래와 같이 작성시 내가 사용하는 DB를 사용하겠다는 의미이다.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
추가적으로 H2 사용하는 방법을 적어보려고 한다.
1. 의존성 추가
2. test properties 생성 및 설정
3. @ActiveProfiles("test")를 테스트 코드에 작성
'Server Development > Testing' 카테고리의 다른 글
Integration Test (0) | 2023.08.04 |
---|---|
Apache Jmeter (0) | 2023.05.15 |
Test Coverage with Jacoco (0) | 2023.04.02 |
Unit Test with MVC (0) | 2023.04.02 |
Swagger (0) | 2023.04.01 |