엑셀 다운로드를 위해 poi 라이브러리를 사용중인데 관련 클래스 생성자에서 Workbook 을 생성하는 부분이 static 으로 처리되고 있어서
단위테스트 할 때 NPE 가 터지는 부분을 어떻게 처리 했는지 기록해보려고 한다.
외부 DI 를 직접 만들어주자
이전부터 유투브에 백기선님의 영상을 종종 보던게 있는데 외부 서비스를 호출하는 것은 어떻게 테스트할 것인가 ? (이걸 모르면 공부 제대로 하지 않았다는 말에 늘 보고 또 보고 잊어먹으면 또 보고 하던 영상) 이 있었는데 이럴 때 쓰라고 있는 것 같아서 시도해봤다.
현재 ExcelWriter 라는 클래스 생성자는 다음과 같다.
public ExcelWriter(Resource resource) throws IOException {
this.workbook = WorkbookFactory.create(resource.getInputStream());
this.sheet = workbook.getSheetAt(0);
}
WorkbookFactory.create
가 poi 에서 사용되는 static 메소드이다.
그래서 처음엔 대략적으로 아래처럼 코드를 짰다. (실제와 다르며 예시일 뿐 틀린 부분이 있을 수 있음)
class ExcelTest {
@InjectMocks
private ExcelService excelService;
@Mock
private WorkbookFactory workbookFactory;
@Mock
private Awss3Service awss3Service;
interface WorkbookFactory {
Workbook create(InputStream inputstream);
}
class DefaultWorkbookFactoryService impletements WorkbookFactory {
@Override
public Workbook create(InputStream inputStream) {
return new XSSWorkbook();
}
}
@Test
void 엑셀_다운로드() {
final Resource excelForm = new ByteArrayResource("test.xlsx".getBytes());
given(awss3Service.getExcelForm("test")).willReturn(excelForm);
DefaultWorkbookFactoryService workbookService = new DefaultWorkbookFactoryService();
given(workbookService.create(any(InputStream.class))).willReturn(any(XSSWorkbook.class));
excelService.download();
}
}
class ExcelService {
void download() {
final Resource excelForm = awss3Service.getExcelForm("test");
ExcelWriter<TestInfo> excelWriter = new ExcelWriter<>(excelForm);
}
}
위 처럼이거나 workbookFactory 에 대해 다른 방법으로 수정을 했어야 하는건지 사실 영상과는 다르게 뭔가 제대로 되지 않았다.
mockStatic 사용
static 메소드 자체를 mock 처리 하는 방법이 있어서 해당 부분을 사용해 봤다.
@Test
void 엑셀_다운로드() {
final Resource excelForm = new ByteArrayResource("test.xlsx".getBytes());
given(awss3Service.getExcelForm("test")).willReturn(excelForm);
try (MockedStatic<WorkbookFactory> workbookFactoryMockedStatic = mockStatic(WorkbookFactory.class)) {
given(WorkbookFactory.create(any(InputStream.class))).willReturn(any(Workbook.class));
excelService.download();
}
}
위 처럼 진행하니 static 메소드 호출 부분인 WorkbookFactory.create()
는 넘어 갔으나 return 값이 null 이 되는 바람에this.sheet
부분에 할당 하는 부분에서 NPE 가 발생했다. 그래서 아래처럼 다시 코드를 수정
@Test
void 엑셀_다운로드() {
final Resource excelForm = new ByteArrayResource("test.xlsx".getBytes());
given(awss3Service.getExcelForm("test")).willReturn(excelForm);
try (MockedStatic<WorkbookFactory> workbookFactoryMockedStatic = mockStatic(WorkbookFactory.class)) {
Workbook mockedWorkbook = new XSSFWorkbook();
mockedWorkbook.createSheet();
workbookFactoryMockedStatic.when(
() -> WorkbookFactory.create(any(InputStream.class))
).thenReturn(mockedWorkbook);
excelService.download();
}
}
sheet 를 하나 생성한 다음 return value 에 직접 넣으니 성공하였음.
이게 맞나 ?
구글링을 해보니 static 을 모킹하지 말고 추상화를 새로하여 사용하는 것을 권장하는 것 같았다.
그래서 이 부분이 상단의 유투브 영상과 같은 내용이 아닌가 싶었음... 하지만 제대로 되지 않아 일단 모킹해서 사용했는데 하나라도 되니까 일단 만족
'Backend > Spring' 카테고리의 다른 글
해외 IP 차단 (0) | 2024.06.25 |
---|---|
Spring Boot 3 + Swagger 3 적용 (0) | 2024.03.03 |
Spring 3.0 Rest Docs requestParameters Removed (0) | 2023.08.04 |
[GS인증] 데이터 암호화 처리 > AES-128 알고리즘 (0) | 2023.07.25 |
POI -> 대용량 데이터 Excel 다운로드 (0) | 2023.03.02 |