본문으로 바로가기

Static Method Mock 처리하기

category Backend/Spring 2023. 10. 5. 14:46
728x90
반응형

엑셀 다운로드를 위해 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 을 모킹하지 말고 추상화를 새로하여 사용하는 것을 권장하는 것 같았다.

그래서 이 부분이 상단의 유투브 영상과 같은 내용이 아닌가 싶었음... 하지만 제대로 되지 않아 일단 모킹해서 사용했는데 하나라도 되니까 일단 만족

728x90
반응형