본문으로 바로가기
반응형

개요

프로젝트를 시작하기 전 가장 중요한 점이 있는데 바로 일관적인 코드가 유지될 수 있도록 하는것이다. 이는 코드 관점에서는 아키텍처와 규칙이 될 수 있겠고 컨벤션 관점에서는 포맷팅이 있을 것 같다. 사람이 코드 포맷팅을 직접 지키면서 작업하기는 힘들기 때문에 일반적으로 플러그인 등의 기능을 이용하여 모든 코드에 일관성을 지키는데 이를 도와주는 것이 바로 Spotless이다. Spotless를 사용하면 현재의 코드가 정해진 규약을 충족하는지 체크할 수 있고 충족하지 않는다면 자동으로 코드를 변경해주는 기능 또한 제공한다.

또한 모든 코드는 테스트 코드가 필수적으로 들어가는데, 사람이 직접 엣지 케이스를 찾아내는건 쉽지 않은 일이다. 이때 코드 커버리지를 측정하는 방법을 도입할 수 있는데 이는 실제로 굉장히 많은 도움이 된다. 자바 진영에서는 이런 코드 커버리지 측정을 위해 Jacoco를 사용한다. 해당 플러그인은 현재 코드에 대한 테스트 커버리지를 측정하여 리포트로 제공해주기 때문에 개발자가 손쉽게 확인할 수 있다. 물론, 코드 커버리지에 의존하기보단 직접 엣지 케이스를 도출하는 능력을 기르는게 우선적으로 선행되어야할 것이다.

본 포스팅에서는 Spotless와 Jacoco에 대한 설정 방법에 대해 간단하게 다뤄보겠다.

Spotless

plugins {
    id("com.diffplug.spotless") version "6.20.0"
}

먼저 build.gradle.kts 파일을 열고 spotless를 플러그인으로 추가한다.

spotless {
	java {
		trimTrailingWhitespace()
		indentWithTabs()
		indentWithSpaces(4)
		endWithNewline()
		googleJavaFormat("1.10.0").aosp().reflowLongStrings()
		formatAnnotations()
		removeUnusedImports()
		importOrder(
				"java",
				"jakarta",
				"lombok",
				"org.springframework",
				"",
				"\\#",
				"org.junit",
				"\\#org.junit",
				"com.teamhide",
				"\\com.teamhide"
		)
	}
}

다음으로 위 코드를 추가해준다. 각 항목별로 어떠한 작업을 하는건지는 네이밍만 봐도 유추할 수 있을 것이다. 

./gradlew spotlessCheck

이제 위 명령어를 통해 현재 코드가 정의한 컨벤션을 지키고 있는지 검사할 수 있다. 최초로 프로젝트를 생성하고 위 명령어를 실행하면,

  Run './gradlew :spotlessApply' to fix these violations.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 760ms

위처럼 실패하는모습을 볼 수 있고 그 위쪽으로 컨벤션에 어긋난 코드 목록을 보여준다. 

./gradlew spotlessApply

이때 위 명령어를 실행하면 정의한 컨벤션을 적용할 수 있다.

Jacoco

plugins {
	id("jacoco")
}

플러그인에 jacoco를 추가해준다.

tasks.jacocoTestReport {
	reports {
		html.required.set(true)
		xml.required.set(false)
		csv.required.set(false)
	}
}

테스트 리포트 관련 설정을 진행한다. 나는 HTML파일로만 제공받고싶기 때문에 해당 부분만 true처리해줬다.

tasks.jacocoTestCoverageVerification {
	violationRules {
		rule {
			enabled = true
			element = "CLASS"
			limit {
				counter = "LINE"
				value = "COVEREDRATIO"
				minimum = "1.00".toBigDecimal()
			}
		}
	}
}

다음으로 테스트 조건에 대한 룰을 명시해준다. 위에 보면 minimum에 100% 모든 부분이 테스트되어야한다고 명시해줬다. 그리고 element에 CLASS를 줌으로써 클래스 단위로 커버리지를 측정하도록 해줬고, counter에 LINE을 줌으로써 빈 줄을 제외한 실제 코드의 라인 수를 기준으로 코드 커버리지 지표를 측정하도록 해주었다.

이제 오른쪽 Gradle탭에서 Tasks - verification쪽을 보면 위에서 설정한 2개의 태스크가 있음을 확인할 수 있다. jacocoTestConverageVerification은 내가 원하는(위에서 설정한 minimum) 커버리지 기준을 충족하는지 검사한다. 그리고 jacocoTestReport는 커버리지에 대한 리포트를 만들어준다.

./gradlew test를 통해 테스트 코드를 실행해보면 build/reports/jacoco/index.html 파일이 생성되고 해당 파일을 통해 커버리지 리포트를 확인할 수 있게 된다.

ETC

lombok.config

config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
lombok.setter.flagUsage = error
lombok.allArgsConstructor.flagUsage = error

루트 디렉토리에 lombok.config파일을 만들고 위와 같은 내용을 추가한다. 각 라인별로 설명하자면,

  • 롬복이 생성한 코드를 상위 클래스에 전파하지 않도록 하는 옵션이다. 예를 들어 @Getter 어노테이션을 사용하여 클래스의 필드에 게터 메소드를 생성하려하면, 롬복은 해당 게터 메소드를 하위 클래슬 뿐만 아니라 상위 클래스에도 생성하려고 시도한다. 이 속성을 꺼줌으로써 클래스간 상속할 때 롬복 코드가 덮어쓰이지 않도록 한다.
  • 롬복으로 인해 생성된 코드에 자동으로 @Generated를 붙여주도록 한다. 이렇게 함으로써 롬복에 의해 생성되었음을 알리고, Jacoco가 테스트 커버리지를 측정할 때 롬복에 의해 생성된 메소드는 테스트 대상에서 제외시키게 된다.
  • 무분별한 setter를 막기 위해 설정한다.
  • 무분별한 전체 인자 생성자를 막기 위해 설정한다.

logback-spring.xml

일반적으로 Slf4j 구현체로 logback을 많이 사용할텐데, 관련해서 로그 설정을 해주는것이 좋다. src/main/resources 하위에 logback-spring.xml 파일을 생성하고 내용을 채워넣는다.

<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %green(%logger{36}) - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="logstash" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <timeZone>UTC</timeZone>
        </encoder>
    </appender>

    <springProfile name="default | test">
        <root>
            <appender-ref ref="stdout" />
        </root>
    </springProfile>
    <springProfile name="prod">
        <appender-ref ref="logstash" />
    </springProfile>
</configuration>

default 또는 test 프로필로 설정했을 때 stdout으로 정의한 형태로 로그를 출력하고 prod인 경우 logstash로 설정한 로그로 출력하는 설정이다.

반응형