자바에서 클래스패스 기반 파일 접근 방법, 그리고 IntelliJ에 적용하기

Cripping File Path

테스트에서 파손된 파일 경로(Cripping File Path)란 말이 있다. 테스트를 수행할 때 특정 경로에 있는 파일을 참조하도록 만들어 놓은 경우를 말한다. OS가 다르거나, 프로젝트 경로가 다른 개발자라면 꽤 짜증 나는 상황일 수밖에 없다.
'가능만 하다면 무조건 상대 경로를 사용하고 절대 경로는 마지막의 마지막까지 미뤄라...... 그리고 특정 테스트 클래스에서만 사용하거나, 같은 패키지 안의 테스트 클래스들에서만 사용하는 파일이라면 자바의 클래스패스로 파일에 접근하는 것이 좋다.'
이는 Effective Unit Testing 이란 책에서 권하는 방법이다.


클래스패스로 파일에 접근

String filePath = getClass().getResource("sample.txt").getFile();
File resource = new File(filePath)

현재 클래스가 위치한 경로를 기준으로 sample.txt 파일을 찾는다. 테스트 클래스와 파일을 같은 경로에 두고 개발을 한다면, 파일의 실제 경로는 전혀 신경 쓸 필요 없이 로직에만 집중하는 방법이다. 
그런데 디렉토리에 공백이 있다면 아래와 같이 URL 인코딩되어 파일을 찾지 못할 수도 있다. 
C:/ykd%20test/gairin/src/test/java/util/file/sample.txt
그러므로 안전하게 아래처럼 처리하는 것이 더 나은 방법이다.

String filePath = this.getClass().getResource("sample.txt").toURI( ).getPath());
System.out.println(filePath);
File file = new File(this.getClass().getResource("sample.txt").toURI());


IntelliJ에서 테스트 수행 시 에러 발생

IntelliJ에서 아래와 같이 모듈 소스 경로를 설정했다. 
그리고 src/test/java/util/file 경로에 테스트 Java 소스와 테스트 Java 소스에서 읽어들이는 파일을 같이 저장했다. 그리고 JUnit 테스트를 돌려보면, 예상과 달리 결과는 실패였다. 실패가 발생하는 이유를 찾아보니 Java 소스는 컴파일되어 output 경로에 클래스파일이 잘 저장되는데, 읽어 들일 파일이 output 경로에 저장되지 않아 생기는 문제였다. 
원인은 IntelliJ에서 Compiler가 처리하는 Resource Pattern에 포함된 확장자가 아니면, output 경로로 보내지 않기 때문이었다. 


해결방법

간단한 처리 방법은 Build > Compiler 메뉴에서 Resource Patterns에 사용할 파일의 확장자를 추가해 주는 것이다. 그러나 간단하기는 하지만, 좋은 방법은 아닐 것 같다. 다른 확장자가 추가될 때마다 수정을 해줘야 하기도 하고, 다른 모듈에 영향을 주게 될 것도 같기 때문이다. 


더 좋은 해결방법

Maven을 이용하는 경우 resource를 지정하여 해결할 수 있다. include, 또는 exclude를 기술하면 좀 더 상세한 조정을 할 수 있다. 그리고 Module이 Maven을 사용하는 경우, IntelliJ에는 추가 설정을 할 필요가 없다. 모듈을 빌드할 때 자동으로 pom.xml의 내용을 참조하여 수행하기 때문이다. 

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <excludes>
                <exclude>**/*.java</exclude>
            </excludes>
        </resource>
    </resources>
    <testResources>
        <testResource>
            <directory>src/test/java</directory>
            <excludes>
                <exclude>**/*.java</exclude>
            </excludes>
        </testResource>
    </testResources>
</build>


참조

http://cpaul.is-programmer.com/posts/25131.html
https://stackoverflow.com/questions/17699754/confused-about-how-intellij-compiles-things-and-deals-with-resources/17699988#17699988
https://stackoverflow.com/questions/4509309/in-maven-how-can-i-include-non-java-src-files-in-the-same-place-in-the-output-ja

댓글 쓰기

0 댓글