자바&스프링부트 프로젝트에서 CSV 파일을 파싱하고, 테스트하는 코드를 작성하는 법을 기록으로 남겨둔다.

CSV 파일 파싱

import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class FileParser {

    private ArrayList<Map<String, String>> processingData(BufferedReader bufferedReader) throws IOException {
        ArrayList<Map<String, String>> data = new ArrayList<>();

        String headerLine = bufferedReader.readLine();
        String[] headers = headerLine.split(",");

        String line;
        while ((line = bufferedReader.readLine()) != null) {
            String[] rows = line.split(",");
            if (rows.length == headers.length) {
                Map<String, String> map = new HashMap<>();
                for (int i = 0; i < rows.length; i++) {
                    String key = headers[i].trim();
                    String value = rows[i].trim();

                    map.put(key, value);
                }
                data.add(map);
            }
        }
        return data;
    }

    // http 요청으로 오는 스트림 파일 처리 (오버로딩)
    public ArrayList<Map<String, String>> convertCsvFile(MultipartFile file) {
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
            // InputStreamReader: 보조 스트림&문자 스트림 (바이트 단위로 읽은 자료를 문자로 변환해주는 보조스트림)
            // BufferedReader: 네트워크 읽거나 쓸 때 사용하는 스트림 (이유: 바이트 자료만 입력되는 스트림이기 때문)
            return processingData(bufferedReader);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 파일 위치 정보가 주어질 경우 처리 (오버로딩)
    public ArrayList<Map<String, String>> convertCsvFile(String file) {
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
            // BufferedReader: 보조 스트림 (스트림 버퍼를 제공해 빠르게 처리 가능)
            // FileReader: 기반 스트림&문자 스트림 (한글은 바이트스트림 대신 문자스트림 사용해야)
            return processingData(bufferedReader);
        } catch (FileNotFoundException e) {
            throw  new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

파일 PATH 테스트

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;

@ActiveProfiles("test")
@SpringBootTest
@AutoConfigureMockMvc
public class MainTests {
    @Autowired
    protected MockMvc mockMvc;

    @Autowired
    protected ObjectMapper mapper;
}

import com.limhm.MainTests;
import com.limhm.common.FileParser;
import org.junit.Test;
import org.junit.jupiter.api.DisplayName;

import java.util.ArrayList;
import java.util.Map;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

public class FileParserTest extends MainTests {
    @DisplayName("csv 파일 파싱 테스트")
    @Test
    public void success() {
        FileParser fileParser = new FileParser();
        ArrayList<Map<String, String>> result = fileParser.convertCsvFile("./src/test/resources/test.csv");

        Map<String, String> map1 = result.get(0);
        assertThat(map1.get("영어")).isEqualTo("abc");
        assertThat(map1.get("한글")).isEqualTo("가나다");
        assertThat(map1.get("숫자")).isEqualTo("010");

        Map<String, String> map2 = result.get(1);
        assertThat(map2.get("영어")).isEqualTo("xyz");
        assertThat(map2.get("한글")).isEqualTo("마바사");
        assertThat(map2.get("숫자")).isEqualTo("234");
    }
}

HTTP 요청 Controller 테스트

import com.limhm.MainTests;

import org.junit.Test;
import org.junit.jupiter.api.DisplayName;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

public class FileControllerTest extends MainTests {
    @DisplayName("파일 테스트")
    @Test
    public void success() throws Exception {
        String PATH = "/registrationFile";
        MockMultipartFile file = new MockMultipartFile(
                "parameter_name",
                "sample.csv",
                MediaType.TEXT_PLAIN_VALUE,
                ("name,item\n" + "kim,gift1\n" + "lee,gift2\n").getBytes()
        );

        MultiValueMap<String, String> dto = new LinkedMultiValueMap<>();
        dto.add("key", "1000001");

        mockMvc.perform(multipart(PATH)
                        .file(file)
                        .header("JWT", "ey")
                        .params(dto))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(print());
    }
}