코드를 개발하면서, 과연 개발한 코드가 정상적으로 작동하는지 테스트를 하는 과정이 동반된다.
나도 프로젝트를 진행하면서 셀 수 없이 테스트를 진행하였다.
테스트를 최대한 자세히, 많이 하여 버그를 줄이는 것이 테스트의 목적이다.
버그를 아예 없애는건 불가능하다.
- 이 사진은 버그 발견 시간이 늦어짐에 따라 비용이 기하급수적으로 커지는 걸 보여준다.
실제로 즐겨하고 있는 게임에서도 뒤늦게 확률형 아이템의 로직에 버그가 발견되어서 2년동안의 기간에 대한 환불을 진행했었다.
사실 여태까지 진행했던 테스트는 실재로 사용자의 입장이 되어서 직접 값을 입력하거나 하는 형태로만 진행을 했었다.
그에 따라 테스트로 인한 Database에 변화가 항상 이루어졌고,
테스트를 할때마다 DB의 테이블을 Drop하는 과정이 있었다.
이렇게 진행했던 이유는 간단했었다.
테스트 하는 API가사용자의 입력
이나,사용자의 정보
를 받아 객체를 생성하여 다루는데,
객체간의 의존성도 생기면서 단위테스트용 입력이나, 정보를 입력하는 방법을 알지 못했었다.
Mockito
는 개발자가 동작을 직접 제어할 수 있는 가짜 객체를 지원하는 테스트 프레임워크이다.
Mockito를 활용하면 가짜 객체에 원하는 결과를 Stub하여 단위 테스트를 진행할 수 있다.
- Mock 객체 의존성 주입
@Mock
: 가짜 객체를 만들어 반환해주는 어노테이션
@Spy
: Stub하지 않은 메소드들은 원본 메소드 그대로 사용하는 어노테이션
@InjectMocks
:@Mock
또는@Spy
로 생성된 가짜 객체를 자동으로 주입시켜주는 어노테이션
- Stub로 결과 처리
의존성이 있는 객체는 가짜 객체를 주입하여 어떤 결과를 반환하라고 정해진 답변을 준비시켜야 한다.
Mockito에서는 다음과 같은 stub 메소드를 제공한다.
doReturn()
: 가짜 객체가 특정한 값을 반환해야 하는 경우doNothing()
: 가짜 객체가 아무 것도 반환하지 않는 경우(void)doThrow()
: 가짜 객체가 예외를 발생시키는 경우
나는 BDDMockito를 사용하여 다음과 같이 결과를 정해주었다.
- Mockito와 Junit의 결합
Mockito도 테스팅 프레임워크이기 때문에 JUnit과 결합되기 위해서는 별도의 작업이 필요하다.
기존의JUnit4
에서 Mockito를 활용하기 위해서는 클래스 어노테이션으로@RunWith(MockitoJUnitRunner.class)
를 붙여주어야 연동이 가능했다.
하지만SpringBoot 2.2.0
부터 공식적으로 JUnit5를 지원함에 따라,
이제부터는@ExtendWith(MockitoExtension.class)
를 사용해야 결합이 가능하다.
출처: https://mangkyu.tistory.com/145 [MangKyu's Diary:티스토리]
given
-when
-then
의 구조로
given
: 테스트를 위한 테스트케이스를 만들어주고when
: 테스트케이스에 대한 함수를 실행하고then
: 함수의 결과가 올바른지 검사하는 형태이다.
assertEquals(a,b)
: 값비교
assertNotNull(대상, 실패시 메시지)
: Null 여부 체크
assertThrows(Exception.class, () -> 테스트대상 메소드)
: 예외 발생 테스트*assertDoesNotThrow(() -> Do)
: *예외 발생 X 테스트
기존에 테스트를 하게되면 Postman이나, 로컬 서버에 접속하여 사용자의 입장이 되어 직접 입력을 하고, 출력되는 값을 보고 코드가 제대로 작동하는지 판단했었다.
Mockito
를 통해 간단하게 여러개의 테스트를 진행하고 확인도 간단하게 진행 할 수 있게 되었다.
Controller의 테스트의 경우 @WebMvcTest 어노테이션을 통해 진행할 수 있다.
진행했던 프로젝트는Spring Security
를 통해 사용자의 인증과 인가를 진행했기에, 테스트를 위해 가짜MockSpringSecurityFilter
를 만들고, 가짜 사용자 정보도 만들어주고 진행을 하였다.
Client에서 오는 입력은JSON 데이터
로 오게되는데,
이를 Dto객체로 맵핑하기위해objectMapper.writeValueAsString
을 사용한다.
그리고MediaType.APPLICATION_JSON
을 통해 JSON 타입임을 알려준다.
기존에 테스트를 하기위해
Postman
에JWT 토큰
과 Body에JSON 데이터
를 직접 입력했었는데,
이제는 손쉽게 테스트 할 수 있게 되었다.
저번에 JUnit에 대해 배웠지만 객체가 의존성을 가지게 되면서 사용할 엄두가 나지않아 일일히 수작업으로 사용자의 입장이 되어 테스트를 진행했었다.
View도 구현하지 않아서 Postman으로 JSON 데이터를 직접 타이핑하고,
테스트 할때마다 로그인을 매번해주고, 반환받은 JWT토큰을 매번 복붙해줬었다...
Swagger를 사용했음에도 테스트를 위해 Postman에도 API정리를 강제로 하게 되었다.
하지만 이제는 쉽게 테스트 할 수 있게되어 다행이다.
내일부터 팀 프로젝트 시작이다.
프로젝트를 진행할때마다 성장이 눈에 보여서 이번 프로젝트도 기대가 된다.