티스토리 뷰
지금까지 Mock이랑 MockMultipartFile을 이용해서 단위 테스트를 했었다. 그 떄까지는 순조로웠던 단위 테스트...
하지만 한 Service의 함수 한에 Util용으로 만들어둔 다른 클래스의 static 메소드를 호출하는 부분이 있었다.
바로 위와 같은 형식의 함수였다. 파일을 업로드하고 가져오고 삭제하고 디렉토리를 정리하는 등의 파일 관련된 공통 기능들이 들어 있는 FIleUtil이 Service 함수 중간 중간에 들어 있는데 특히 위와 같이 uploadFile()과 같이 파일을 업로드 하는 함수가 들어있는 TestService.method()와 같은 것을 테스트 하려고 하니까 FileUtil.uploadFile()이 작동해 계속 이상한 파일이 만들어지는 현상이 발생했다.
게다가 다른 함수에서는 FileUtil 함수 안에서서 파일 관련 Mock으로 사용한 repository 때문에 에러가 나기도 해서 서비스 단에 있는 다른 클래스의 static 함수를 mock을 이용해서 가짜로 만들어 service 로직만 돌릴 수는 없나 방법을 찾아봤다.
static 함수 가짜로 사용할 수 있는 MockedStatic
당연히 Mock에서는 static 함수를 가짜로 사용하기 위한 기능을 제공했다. 바로 MockedStatic!!
MockedStatic을 이용해서 static 함수가 있는 클래스를 정의하면 해당 클래스에 when을 이용해서 static 함수가 사용되었을 때 어떤 동작을 할 것인지 등을 정의해서 서비스 로직 자체만의 단위 테스트를 할 수 있게 된다.
dependency 설정하기
MockedStatic은 그냥 사용할 수 있지만 그냥 사용할 경우 아래 에러가 발생한다.
그러므로 MockedStatic 예제 코드를 보기 전에 미리 dependency 설정부터 해보자.
위의 내용을 간단하게 요약하면 현재 static mock를 생성할 수 있는 설정이 되어 있지 않으므로 'mockito-core'를 사용하고 있다면, 'mockito-inline'을 추가하라는 뜻이다.
하지만 Android에서는 mokito-inline이 지원되지 않는다는 뜻이다.
이 글에서는 mockito-line을 이용해서 static mock 기능을 사용해보겠다.
mockito-line dependency 추가
- gradle
testImplementation 'org.mockito:mockito-inline:3.11.2'
- maven
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
mockito-inline을 사용하기 위한 다른 라이브러리 추가
mockito-inline 라이브러리만 추가하고 다시 mock static 기능을 사용하면 아래와 같은 에러가 발생한다.
java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMaker
MockMaker를 초기화 할 수 없다는 에러인데 mockito-inline을 사용하기 위한 다른 라이브러리들을 추가해야한다.
그것들은 MVNRepository 사이트에서 mockito inline을 검색해서 해당 버전 별로 찾아볼 수 있다.
mockito-core 버전 3.11.2를 종속성 추가했을 경우 아래와 같은 라이브러리들을 추가하면 된다.
- gradle
implementation 'com.google.code.findbugs:findbugs-annotations:3.0.1'
implementation 'net.java.dev.jna:jna:5.8.0'
implementation 'net.java.dev.jna:jna-platform:5.8.0'
- maven
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>findbugs-annotations</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.8.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.8.0</version>
</dependency>
총 dependency 설정
위를 종합해보면 각각 dependency 설정은 아래와 같다. 이와 같이 설정하면 더 이상 mock static 기능에서 에러가 발생하는 일은 없다.
- gradle
implementation 'com.google.code.findbugs:findbugs-annotations:3.0.1'
implementation 'net.java.dev.jna:jna:5.8.0'
implementation 'net.java.dev.jna:jna-platform:5.8.0'
testImplementation 'org.mockito:mockito-inline:3.11.2'
- maven
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>findbugs-annotations</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.8.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.8.0</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.11.2</version>
<scope>test</scope>
</dependency>
Mock Static 기능 예제
위의 설정들을 모두 마쳤다면 이제 테스트 코드에서 아래와 같이 mock static 기능을 사용할 수 있다.
MockedStatic<FileUtil> mFileUtil = mockStatic(FileUtil.class)
위와 같이 static 함수가 있는 클래스를 mockStatic(classType)으로 생성하면 MocakedStatic<classType>으로 반환되는 객체가 생성된다.
그렇게 생성한 객체는 아래와 같이 사용할 수 있다.
mFileUtil.when(() -> FileUtil.method(Mockito.any()).thenReturn("test");
즉 지금까지 when()안에 여러가지 기능들을 넣어놓고 thenAnswer하던거나 thenReturn하던 것을 이제는 static 함수에 when-then을 붙여서 사용할 수 있는 것이다.
참고로 MockedStatic<T>의 when 안에는 그냥 전제 동작인 메소드를 넣는 것이 아닌 '() -> ' 처럼 람다식을 이용해서 넣어야 한다.
또한 MockedStatic<T>는 imputStream/outputStream처럼 close를 해줘야 한다. 그래서 아래와 같이 try 안에 사용 한다. 테스트 코드에서 사용한 자원은 그 테스트 코드 안에서만 사용되야 하므로 close를 하는 것이다.
@Test
void Tests() {
try (MockedStatic<FileUtil> mFileUtil = mockStatic(FileUtil.class)) {
...
mFileUtil.when(() -> FileUtil.method(Mockito.any())).thenReturn("test");
...
// FileUtil.method()가 포함된 service method
}
}
위의 식으로 try 안에 쓰는게 기본이고 그 밖에 junit의 @BeforeClass/@AfterClass 등에 넣어서 미리 생성하는 방법도 있다.
이 방법에 대해서는 다음에 글을 올려보도록 하겠다.
'Java' 카테고리의 다른 글
Factory Pattern(팩토리 패턴)이란? (1) | 2021.08.07 |
---|---|
[ Lombok ] dependency 설정을 했으나 lombok 어노테이션 에러 발생시 해결 방법 (1) | 2021.07.28 |
[ Enum ] AttributeConverter를 이용해 DB에 값 그대로 저장하기 (0) | 2021.07.20 |
[ Enum ] JPA로 enum name 그대로 DB에 저장하기(@Enumerated) (0) | 2021.07.19 |
[ Enum ] JSON parse error: Cannot deserialize value of type (0) | 2021.07.18 |
- Total
- Today
- Yesterday
- DATABASE
- springboot
- 데이터베이스
- PostgreSQL
- k8s
- 메시지큐
- eclipse
- ssh
- postgres
- Caching
- DB
- 스프링부트
- enum
- Java
- mockito
- 이클립스
- 자바
- 캐싱
- Intellij
- rabbitmq
- cache
- Spring
- annotation
- 역직렬화
- JPA
- 공간데이터
- HttpClient
- 캐시
- 어노테이션
- MAC
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |