그레들로 프로젝트의 테스트를 실행할때마다
테스트에서 사용하는 자원파일을 찾을 수 없다고 나오길래

왜 못찾는 것이냐?

라고 무시하고(?) 넘어간지 3개월여만에...
그레들 문서(https://docs.gradle.org/current/userguide/java_plugin.html)를 보면서 확인한지 30여분만에 문제를 발견.

src/test/resource

...

src/test/resources

였어야 했는데 말이지...!!! 크앙!!
결함이 발생하던 테스트들 수정하고 정상동작하는 것 확인.

그런데 말입니다.
왜 유닛테스트는 통과되었던거지??


코드의 품질을 높이기 위해서 많이 사용되는 것이 코드에 대한 정적분석을 통해서 코드의 품질을 평가하는 것이다.

코드정적분석에 사용되는 도구로는 checkstyle, findbugs, PMD 등 이 있다. 그레들gradle에 checkstyle, PM 를 추가하는 방법을 설명한다.

1. checkstyle

1.1. 사용방법

1.1.1. gradle's checkstyle 플러그인 추가

apply plugind: 'checkstyle'

build.gradle 파일에 플러그인을 추가한다.

1.1.2. checkstyle.xml 작성

1.1.3. build.gradle 파일에 checkstyle 태스크를 정의한다.

checkstyle {
  ignoreFailures = true // 분석결과 예외가 발생하면 빌드실패 발생시키는 것을 제외
    configFile = file("checkstyle.xml") // 1.1.2 에서 작성한 checkstyle 파일 지정
    reportsDir = file("${buildDir}/checkstyle-output") // 리포트 파일이 위치할 디렉토리 지정
}
 
checkstyleMain {
    reports {
        xml.destination = file("${checkstyle.reportsDir}/checkstyle-report.xml") // 리포트 파일의 위치 및 파일명 지정
    }
}

1.1.4. checkstyle 실행

$ gradle check

checkstyle 플러그인을 추가하면 그레들의 check 태스크를 수정하여 checkstyle 의 checkstyleMain, checkstyleTest 들을 실행시킨다.

1.2. 태스크Tasks

Task nameDepends onTypeDescription
checkstyleMainclassesCheckstyleRuns Checkstyle against the production Java source files.
checkstyleTesttestClassesCheckstyleRuns Checkstyle against the test Java source files.
checkstyleSourceSetsourceSetClassesCheckstyleRuns Checkstyle against the given source set's Java source files.

1.3. checkstyle.xml 기본구조

<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
          "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
          "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
 
<module name="Checker">
    <property name="charset" value="UTF-8" />
    <property name="severity" value="warning" />
    <property name="fileExtensions" value="java, properties, xml" />
 
    <module name="TreeWalker">
        <!-- 사용되는 모듈과 모듈속성을 정의-->
    </module>
</module>

2. PMD

2.1. 사용방법

2.1.1. gradle's pmd 플러그인 추가

apply plugind: 'pmd'

build.gradle 파일에 플러그인을 추가한다.

2.1.2. pmd 태스크의 속성을 정의한다.

pmd {
  ignoreFailures = true // 분석결과 예외가 발생하면 빌드실패 발생시키는 것을 제외
    reportsDir = file("${buildDir}/pmd-output")
}
 
pmdMain {
    reports {
        xml.destination = file("${pmd.reportsDir}/pmd-report.xml")
        xml.enabled = true
    }
}

2.1.3. 실행

$ gradle check

PMD 플러그인이 check 태스크에 의존성을 추가한다.

2.2. 태스크Tasks

태스크명의존유형설명
pmdMain-Pmd출시 소스파일을 대상으로 PMD 실행
pmdTest-Pmd테스트 소스파일을 대상으로 PMD 실행
pmdSourceSet-Pmd지정된 소스셋SourceSet을 대상으로 PMD 실행

3. 정리

checkstyle과 pmd 에서 생성한 XML 보고서는 JENKINS에서 사용하기 위한 분석데이터로 사용된다.

JENKINS에서 checkstyle, pmd 플러그인을 설치한 후 report.xml 경로를 지정한 후



빌드가 정상적으로 진행되면서 분석문서가 생기면 다음과 같은 항목들이 왼쪽 메뉴에 추가가 되고,



각각의 결과를 확인할 수 있다.




○ 참고문헌


그레들Gradle에는 래퍼Wrapper라고 하는 운영체제에 맞춰서 그레들 빌드를 수행하도록 하는 배치 스크립트가 있다.
이 배치스크립트는 프로젝트 내에 숨김속성을 가지고 있는 gradle-wrapper.jar 를 이용해서

project
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle

운영체제에 적절한 배치 스크립트를 실행하도록 한다.

  • 윈도우: gradlew.bat
    > gradlew.bat [task]
    
  • 리눅스 및 OSX: gradlew
    $ ./gradlew [task]
    

프로젝트의 성격에 맞춰 사용할 래퍼의 버전을 변경할 수 있도록 별도의 태스크Task를 작성실행할 수 있다.
프로젝트에 위치한 build.gradle 파일의 마지막 부분에 다음과 같이 wrapper 태스크를 추가한 후,

ext {
    gradleVersion= '2.1' //자신이 원하는 Gradle 버전에 맞춰 변경
}

//...중략

task wrapper(type: Wrapper) {
    gradleVersion = "$gradleVersion"
}

wrapper 태스크를 실행하면 된다.

$ gradle wrapper

● 참고


윈도우에서 그레들을 실행해본 적이 없어서(;;) 몰랐던 문제가 이번에 발생을 했다. 인코딩 문제…
다양한 개발환경을 가진 팀이 개발을 할떄도 신경써야 하는 부분이기도 하다. 이클립스의 파일 인코딩을
‘UTF-8’로 바꿨을 때도 이와 유사한 상황이 벌어지지 않을까 하는 생각이 들지만… 그건 그때 가서
살펴보도록 한다.

그레들이 실행될 때, 운영체제의 시스템설정들이 그대로 적용된다. 유닉스나 리눅스에서는 UTF-8로 인코딩이
유지가 되니까 별 무리가 없지만, 윈도우는 MS949 인코딩 처리가 되기에 문제가 발생했다.

발생한 문제는 다음과 같다.

발생문제

클래스 컴파일 시 한글주석을 넣은 클래스들에서 아래의 메시지를 뿌리며 컴파일이 진행되지 않았다.

  • error: unmappable character for encoding MS949
  • error: unclosed string literal

아무런 옵션없이 gradle을 실행하면 다음과 같이 encoding 관련한 오류가 발생을 한다.

C:\Users\ihoneymon\workspace\rocking-the-rest-api\src\main\java\kr\pe\ihoney\jco
\restapi\web\support\converter\AbstractEntityConverter.java:16: error: unmappabl
e character for encoding MS949
 * JPA Entity ?대옒??蹂?솚???꾪븳 異붿긽?대옒??
                      ^
C:\Users\ihoneymon\workspace\rocking-the-rest-api\src\main\java\kr\pe\ihoney\jco
\restapi\web\support\converter\AbstractEntityConverter.java:16: error: unmappabl
e character for encoding MS949
 * JPA Entity ?대옒??蹂?솚???꾪븳 異붿긽?대옒??
                       ^
C:\Users\ihoneymon\workspace\rocking-the-rest-api\src\main\java\kr\pe\ihoney\jco
\restapi\web\support\converter\AbstractEntityConverter.java:16: error: unmappabl
e character for encoding MS949
 * JPA Entity ?대옒??蹂?솚???꾪븳 異붿긽?대옒??
                        ^
C:\Users\ihoneymon\workspace\rocking-the-rest-api\src\main\java\kr\pe\ihoney\jco
\restapi\service\impl\CommunityServiceImpl.java:39: error: unclosed string liter
al
        Member manager = memberService.save(new Member(community.getName() + "
愿?━??, community, community.getCreatedBy()));
                                                                             ^
C:\Users\ihoneymon\workspace\rocking-the-rest-api\src\main\java\kr\pe\ihoney\jco
\restapi\service\impl\CommunityServiceImpl.java:39: error: ')' expected
        Member manager = memberService.save(new Member(community.getName() + "
愿?━??, community, community.getCreatedBy()));

                                            ^
2 errors
:generateQueryDSL FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':generateQueryDSL'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug
option to get more log output.

BUILD FAILED

Total time: 6.63 secs

ihoneymon@IHONEYMON-VIRPC ~/workspace/rocking-the-rest-api (master)
$


윈도우에서는 기본적으로 MS949 을 사용하고 있는데, UTF-8로 작성한 소스코드를 가져와 컴파일하면 위와 같은 문제가 발생한다.

해결방법

gradle을 실행할 때 기본적으로 줄 수 있는 옵션에 file.encoding 을 추가하는 것이다. 윈도우 시스템설정-환경변수에서

GRADLE_OPTS=-Dfile.encoding=UTF-8

을 추가하면 된다.

환경변수 설정을 하고 배쉬나 커맨드라인을 닫고 재실행하여 진행하면 적용된다.

Spring Boot + Gradle 을 이용한 프로젝트 시작할 때 쓸 목적으로 프로젝트를 하나 만들었다.

먼저 로컬에서 작업하고, 깃헙에서 저장소Repository를 만들었다.

  • 빈 저장소에서 친절하게 설명해주는 깃헙씨.
  • http와 ssh 프로토콜 지원하고,
  • 프로젝트를 새로 만들었을 때 깃을 이용하여 등록하고 깃헙에 생성한 저장소에 밀어넣는 방법.
  • 이미 만들어진 저장소를 깃헙에 밀어넣는 방법.
  • 혹은 다른 버전관리시스템에서 불러오는 방법

친절하다.

회사에서 진행하는 프로젝트는 스프링부트Springboot 를 이용해서 진행해보고 싶은 욕심이 생겼다.


 

기타 참고사항 

 

+ Recent posts