2021. 10. 12. 12:56ㆍBuild Tools/Gradle
1. Gradle, slf4j, logback, junit, assertj
1. Gradle
1. task
하나의 작업 단위를 묶어놓은 것이다. 터미널에서 gradle run
을 입력하면 아래 task
를 실행할 수 있다.
apply plugin: 'java'
task run(type: JavaExec) {
mainClass: 'exercise.HelloWorld'
classpath: sourceSets.main.runtimeClasspath
}
task runAfterCompile(dependsOn: classes, type: JavaExec) {
mainClass: 'exercise.HelloWorld'
classpath: sourceSets.main.runtimeClasspath
}
apply plugin
- 프로젝트에서 사용할 플러그인을 명시한다.
dependsOn
- 이
task
가 의존할gradle
명령어를 지정한다. classes
라고 작성하면 이task
실행 전에gradle classes
, 즉 자바 파일에 대해 컴파일 작업을 수행한다.
- 이
type: JavaExec
run
은JavaExec
을 상속받는task
임을 나타낸다.
mainClass
main
이 정의되어 있는 클래스의 패키지 경로를 지정한다.
classpath
- 프로그램 실행에 있어서 필요한 라이브러리 경로를 지정한다.
sourceSets
gradle
프로젝트 경로 중src
까지의 패키지 경로를 의미한다.
runtimeClasspath
- 런타임에 필요한 라이브러리 경로들을 의미한다.
plugin: application
위의 run
과 같은 task
는 자주 사용되므로 gradle
에서는 application
이라는 플러그인으로 지원한다. 이때 mainClassName
으로 main
이 정의된 클래스를 지정해주면 된다. 이 또한 gradle run
커맨드로 실행할 수 있다.
apply plugin: 'application'
mainClassName = 'exercise.HelloWorld'
2. dependencies
implementation
sourceSets
의 자바 소스를 컴파일 할 때와 런타임 시에 모두 필요한 라이브러리를 지정한다.
runtimeOnly
sourceSets
의 자바 소스를 런타임 시에만 필요한 라이브러리를 지정한다.
compileClasspath
sourceSets
의 자바 소스를 컴파일 할 때 필요한 라이브러리를 지정한다.
gradle dependencies(dep)
- 터미널에서
gradle
프로젝트의 의존성을 확인하는 명령어이다. - 옵션으로 런타임, 컴파일 등 의존성을 분리하여 확인할 수도 있다.
gradle dependencies —configuration runtimeOnly
- 런타임 시 사용되는 의존성만 출력한다.
gradle dependencies —cofiguration runtimeClasspath
- 런타임 시 사용되는 의존성과 연관된 모든 의존성을 함께 표시한다.
gradle dependencies —configuration compileOnly
- 컴파일 시 사용되는 의존성만 출력한다.
gradle dependencies —cofiguration compileClasspath
- 컴파일 시 사용되는 의존성과 연관된 모든 의존성을 함께 표시한다.
gradle dependencies —configuration implementation
- 런타임 및 컴파일 시 사용되는 의존성만 출력한다.
- 터미널에서
3. Logging options
출력되는 로그 레벨도 지정할 수 있다.
- -q, —quiet
- 에러 로그만 출력한다.
gradle -q dep —configuration runtimeOnly
- -w, —warn
- 경고, 에러 로그만 출력한다.
gradle -w dep —configuration runtimeOnly
- -i, —info
- 정보, 경고, 에러 로그만 출력한다.
gradle -i dep —configuration runtimeOnly
- -d, —debug
- 디버그, 정보, 경고, 에러 로그만 출력한다.
gradle -d dep —configuration runtimeOnly
2. slf4j, logback
자바 생태계에서 현재 가장 널리 사용되는 로깅 라이브러리이다. 로그 기능을 사용하려면 사용하려는 클래스에서 loggerfactory
를 통해 logger
를 생성해서 사용한다. 인수로는 사용하는 클래스의 class
객체를 넘겨준다.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jDemo {
private static final Logger log = LoggerFactory.getLogger(Slf4jDemo.class);
public static void main(String[] args) {
String name = "Bill";
Integer age = 37;
log.error("Error Message : ({} {})", name, age);
log.warn ("Warn Message : ({} {})", name, age);
log.info ("Info Message : ({} {})", name, age);
log.debug("Debug Message : ({} {})", name, age);
log.trace("Trace Message : ({} {})", name, age);
System.out.println("End");
}
}
로그 레벨
로그는 5개의 레벨로 구분되어 출력할 수 있다. 우선순위가 높은대로 error
, warn
, info
, debug
, trace
이다. 각 레벨은 각 단어의 뜻과 같은 의미를 가진다. error
는 에러 상황에, warn
은 경고, info
는 변수 정보 같은 개발자에게 유용한 정보, debug
는 디버깅을 할 때, trace
는 모든 메시지에 대해 출력한다.
로그의 기본 레벨은 debug
이며 이때 trace
는 출력되지 않는다. 즉 설정한 레벨에 따라 출력되는 로그가 달라진다.
로깅 라이브러리를 사용하면 로그가 찍힌 시간, 실행 중이던 쓰레드, 로그 레벨과 패키지, 클래스명까지 전부 출력된다. 그리고 로그를 콘솔에 출력할 것인지, 파일에 저장할 것인지, 외부 PC에 저장할 것인지 등까지 선택할 수 있다. System.out.println()
과 같은 메서드는 그저 콘솔에 출력만 할 뿐이다. 그러므로 로깅 라이브러리를 알게 된 시점 이후부터는 로깅 라이브러리를 사용하는 편이 바람직하다.
로그 설정
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%5level) %cyan(%24logger{24})| %msg%n</pattern>
</encoder>
</appender>
<logger name="demo" level="INFO" />
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
appender
- 로그를 출력할 위치를 지정한다. 콘솔, 파일, 외부 PC 전송 등 여러 옵션을 결정한다. 위와 같이
class
를 지정하면 콘솔에 출력된다.name
은 아래appender-ref
에서 참조할 이름이다.
- 로그를 출력할 위치를 지정한다. 콘솔, 파일, 외부 PC 전송 등 여러 옵션을 결정한다. 위와 같이
encoder
- 로그 이벤트를 바이트 배열로 변환하고, 그 배열을
OutputStream
에 쓰는 작업을 수행한다. 이때 내부에 패턴이 있으면 패턴의 형식대로 출력한다.
- 로그 이벤트를 바이트 배열로 변환하고, 그 배열을
pattern
- 로그를 출력할 형식을 지정한다.
logger
name
으로 지정한 패키지 하위의 로그 레벨을 설정한다. 예제에서는demo
하위 패키지들은INFO
레벨로 설정됐다.
root
- 프로젝트에서 사용되는 모든 로그에 대해 레벨을 지정해준다. 이때 의존 라이브러리들의 레벨도 함께 지정된다.
appender-ref
- 로그를 출력할
appender
를 지정해준다. 위에서 작성한STDOUT
을ref
로 작성하면 해당appender
가 반영된다.
- 로그를 출력할
3. JUnit and assertj
테스트는 복잡한 애플리케이션을 개발할 때 오류를 최소화하기 위해 현대 개발에서 필수 요소가 되었다. JUnit
은 자바 생태계에서 가장 많이 사용되는 테스트 프레임워크이다. 그리고 이를 보조해주는 라이브러리로 hamcrest
와 assertj
가 대표적이고 현재 assertj
가 많이 사용된다.
설정
// build.gradle
apply plugin: 'java'
apply plugin: 'application'
application {
mainClass = "demo.HelloWorld"
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.slf4j:slf4j-api:1.7.+'
runtimeOnly 'ch.qos.logback:logback-classic:1.2.+'
testImplementation 'org.junit.jupiter:junit-jupiter:5.6.+'
}
test {
useJUnitPlatform()
outputs.upToDateWhen { false }
testLogging {
events "passed", "skipped", "faile"
showStandardStreams = true
exceptionFormat = "full"
}
afterSuite { desc, result ->
if (!desc.parent) {
println "\nResults: ${result.resultType} " +
"(${result.testCount} tests -> " +
"${result.successfulTestCount} successes, " +
"${result.failedTestCount} failures, " +
"$result.skippedTestCount} skipped)"
}
}
}
dependencies
를 확인하면 testImplementation
에 'org.junit.jupiter:junit-jupiter:5.6.+'
로 적힌 것을 확인할 수 있다. 이는 테스트 시 컴파일, 런타임 시 모두 사용되는 라이브러리로 지정한 것이다. 그리고 JUnit4
에서 JUnit5
로 버전이 업그레이드되면서 패키지명이 변경되었다. 따라서 테스트 코드 작성 시 import
에 주의해야 한다. 또 한 가지 주의해야 할 점은 gradle
프로젝트는 기본적으로 JUnit4
를 기본으로 적용하도록 되어 있다는 것이다. JUnit5
로 설정하려면 test
블럭에 useJUnitPlatform()
을 꼭 작성해주어야 한다.
outputs.upToDateWhen
- 테스트 코드 실행 시 이전에 테스트했던 것에 변화가 없어도 다시 테스트를 수행할 것인지에 대한 여부를 설정한다.
true
- 다시 수행하지 않는다.false
- 항상 테스트를 수행한다.
- 테스트 코드 실행 시 이전에 테스트했던 것에 변화가 없어도 다시 테스트를 수행할 것인지에 대한 여부를 설정한다.
testLogging
- 테스트 로그에 대한 옵션을 지정한다.
events
- 테스트에서 지정한 이벤트에 대해서 출력하도록 하는 옵션이다.
showStandardStreams
- JVM 콘솔 표준 출력을 출력할 것인지 여부를 설정한다.
exceptionFormat
- 콘솔에 기록되는 테스트 이벤트 및 자세한 레벨과 관련된 옵션을 설정한다.
afterSuite
- 테스트가 모두 종료되면 테스트에 대한 종합적인 정보를 출력할 때 사용한다. 첫 번째 인자로
TestDescriptor
, 두 번째 인자로TestResult
인스턴스를 받는다. - 이와 비슷한
afterTest
가 있는데 이는 하나의 테스트가 수행된 후마다 실행된다.
- 테스트가 모두 종료되면 테스트에 대한 종합적인 정보를 출력할 때 사용한다. 첫 번째 인자로
테스트 코드 작성
import java.util.*;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class TestCalculator {
@Test
public void testAdd() {
Calculator cal = new Calculator();
assertThat(cal.add(1, 2)).isEqualTo(3);
}
// JUnit5부터는 public을 제외해도 무방하다.
@Test
void testNumber() {
assertThat(1).isEqualTo(1);
assertThat(1).isNotEqualTo(2);
assertThat(true).isTrue();
assertThat(1 == 2).isFalse();
}
@Test
void testDescribeAssertion() {
assertThat(45)
.as("%s's age should be not equal to 100", "Steve")
.isNotEqualTo(100);
}
}
대부분이 메서드명으로 어떤 테스트를 하는지 알 수 있다. as
는 테스트 시 출력으로 표시할 메시지를 작성하는 것이다.
테스트 커맨드 옵션
gradle test —tests demo.FirstTest
—tests
뒤에 패키지명을 적어주면 그 테스트만 수행한다.- 메서드까지 지정할 수 있다.
gradle test —tests demo.TestCalculator.testAdd
gradle test —tests demo.TestCal*
- 패키지명이
demo.TestCal
로 시작하는 모든 테스트를 수행한다. *anyOf*
로 지정하면 anyOf를 패키지명에 포함하는 모든 테스트를 수행한다.
- 패키지명이
'Build Tools > Gradle' 카테고리의 다른 글
[Gradle] Windows에서 Intellij 프로젝트에서 Test 시 발생할 수 있는 오류 (0) | 2023.03.20 |
---|---|
[Gradle] 빌드 스크립트 더 배우기 (0) | 2023.03.18 |
[Gradle] 빌드 스크립트 기본 (0) | 2023.03.18 |
[Gradle] Gradle 디렉터리 구조 (0) | 2023.03.18 |
[Gradle] 빌드 생명 주기 (0) | 2023.03.18 |