소스 작성중 JUnit 이 임포트가 안되는 문제가 생김.
그래들엔 분명 spring-boot-starter-test 의존성이 있고, 책에선 이게 JUnit5, 모키토, 어서트J 같은 테스트 라이브러리를 프로젝트로 임포트 한다고 써있는데...!
package com.polarbookshop.catalogservice.domain;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.junit.jupiter.api.BeforeAll;
//Book 객체의 유효성 검사 제약조건을 검증하기 위한 단위 테스트
public class BookValidationTests {
private static Validator validator;
@BeforeAll
static void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
}
JUnit4에서 쓰이는
import org.junit.BeforeClass;
도 사용해봤는데 전혀 들어먹지를 않음.
C:\Y\Cloud Native Spring in Action\catalog-service>gradlew.bat dependencies --configuration testRuntimeClasspath
> Task :dependencies
------------------------------------------------------------
Root project 'catalog-service'
------------------------------------------------------------
testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- org.springframework.boot:spring-boot-starter-web -> 3.4.1
| +--- org.springframework.boot:spring-boot-starter:3.4.1
| | +--- org.springframework.boot:spring-boot:3.4.1
| | | +--- org.springframework:spring-core:6.2.1
| | | | \--- org.springframework:spring-jcl:6.2.1
| | | \--- org.springframework:spring-context:6.2.1
| | | +--- org.springframework:spring-aop:6.2.1
| | | | +--- org.springframework:spring-beans:6.2.1
| | | | | \--- org.springframework:spring-core:6.2.1 (*)
| | | | \--- org.springframework:spring-core:6.2.1 (*)
| | | +--- org.springframework:spring-beans:6.2.1 (*)
| | | +--- org.springframework:spring-core:6.2.1 (*)
| | | +--- org.springframework:spring-expression:6.2.1
| | | | \--- org.springframework:spring-core:6.2.1 (*)
| | | \--- io.micrometer:micrometer-observation:1.14.2
| | | \--- io.micrometer:micrometer-commons:1.14.2
| | +--- org.springframework.boot:spring-boot-autoconfigure:3.4.1
| | | \--- org.springframework.boot:spring-boot:3.4.1 (*)
| | +--- org.springframework.boot:spring-boot-starter-logging:3.4.1
| | | +--- ch.qos.logback:logback-classic:1.5.12
| | | | +--- ch.qos.logback:logback-core:1.5.12
| | | | \--- org.slf4j:slf4j-api:2.0.15 -> 2.0.16
| | | +--- org.apache.logging.log4j:log4j-to-slf4j:2.24.3
| | | | +--- org.apache.logging.log4j:log4j-api:2.24.3
| | | | \--- org.slf4j:slf4j-api:2.0.16
| | | \--- org.slf4j:jul-to-slf4j:2.0.16
| | | \--- org.slf4j:slf4j-api:2.0.16
| | +--- jakarta.annotation:jakarta.annotation-api:2.1.1
| | +--- org.springframework:spring-core:6.2.1 (*)
| | \--- org.yaml:snakeyaml:2.3
| +--- org.springframework.boot:spring-boot-starter-json:3.4.1
| | +--- org.springframework.boot:spring-boot-starter:3.4.1 (*)
| | +--- org.springframework:spring-web:6.2.1
| | | +--- org.springframework:spring-beans:6.2.1 (*)
| | | +--- org.springframework:spring-core:6.2.1 (*)
| | | \--- io.micrometer:micrometer-observation:1.14.2 (*)
| | +--- com.fasterxml.jackson.core:jackson-databind:2.18.2
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.18.2
| | | | \--- com.fasterxml.jackson:jackson-bom:2.18.2
| | | | +--- com.fasterxml.jackson.core:jackson-annotations:2.18.2 (c)
| | | | +--- com.fasterxml.jackson.core:jackson-core:2.18.2 (c)
| | | | +--- com.fasterxml.jackson.core:jackson-databind:2.18.2 (c)
| | | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2 (c)
| | | | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2 (c)
| | | | \--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.18.2 (c)
| | | +--- com.fasterxml.jackson.core:jackson-core:2.18.2
| | | | \--- com.fasterxml.jackson:jackson-bom:2.18.2 (*)
| | | \--- com.fasterxml.jackson:jackson-bom:2.18.2 (*)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2
| | | +--- com.fasterxml.jackson.core:jackson-core:2.18.2 (*)
| | | +--- com.fasterxml.jackson.core:jackson-databind:2.18.2 (*)
| | | \--- com.fasterxml.jackson:jackson-bom:2.18.2 (*)
| | +--- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2
| | | +--- com.fasterxml.jackson.core:jackson-annotations:2.18.2 (*)
| | | +--- com.fasterxml.jackson.core:jackson-core:2.18.2 (*)
| | | +--- com.fasterxml.jackson.core:jackson-databind:2.18.2 (*)
| | | \--- com.fasterxml.jackson:jackson-bom:2.18.2 (*)
| | \--- com.fasterxml.jackson.module:jackson-module-parameter-names:2.18.2
| | +--- com.fasterxml.jackson.core:jackson-core:2.18.2 (*)
| | +--- com.fasterxml.jackson.core:jackson-databind:2.18.2 (*)
| | \--- com.fasterxml.jackson:jackson-bom:2.18.2 (*)
| +--- org.springframework.boot:spring-boot-starter-tomcat:3.4.1
| | +--- jakarta.annotation:jakarta.annotation-api:2.1.1
| | +--- org.apache.tomcat.embed:tomcat-embed-core:10.1.34
| | +--- org.apache.tomcat.embed:tomcat-embed-el:10.1.34
| | \--- org.apache.tomcat.embed:tomcat-embed-websocket:10.1.34
| | \--- org.apache.tomcat.embed:tomcat-embed-core:10.1.34
| +--- org.springframework:spring-web:6.2.1 (*)
| \--- org.springframework:spring-webmvc:6.2.1
| +--- org.springframework:spring-aop:6.2.1 (*)
| +--- org.springframework:spring-beans:6.2.1 (*)
| +--- org.springframework:spring-context:6.2.1 (*)
| +--- org.springframework:spring-core:6.2.1 (*)
| +--- org.springframework:spring-expression:6.2.1 (*)
| \--- org.springframework:spring-web:6.2.1 (*)
+--- org.springframework.boot:spring-boot-starter-validation -> 3.4.1
| +--- org.springframework.boot:spring-boot-starter:3.4.1 (*)
| +--- org.apache.tomcat.embed:tomcat-embed-el:10.1.34
| \--- org.hibernate.validator:hibernate-validator:8.0.2.Final
| +--- jakarta.validation:jakarta.validation-api:3.0.2
| +--- org.jboss.logging:jboss-logging:3.4.3.Final -> 3.6.1.Final
| \--- com.fasterxml:classmate:1.5.1 -> 1.7.0
+--- org.springframework.boot:spring-boot-starter-test -> 3.4.1
| +--- org.springframework.boot:spring-boot-starter:3.4.1 (*)
| +--- org.springframework.boot:spring-boot-test:3.4.1
| | +--- org.springframework.boot:spring-boot:3.4.1 (*)
| | \--- org.springframework:spring-test:6.2.1
| | \--- org.springframework:spring-core:6.2.1 (*)
| +--- org.springframework.boot:spring-boot-test-autoconfigure:3.4.1
| | +--- org.springframework.boot:spring-boot:3.4.1 (*)
| | +--- org.springframework.boot:spring-boot-test:3.4.1 (*)
| | \--- org.springframework.boot:spring-boot-autoconfigure:3.4.1 (*)
| +--- com.jayway.jsonpath:json-path:2.9.0
| | +--- net.minidev:json-smart:2.5.0 -> 2.5.1
| | | \--- net.minidev:accessors-smart:2.5.1
| | | \--- org.ow2.asm:asm:9.6
| | \--- org.slf4j:slf4j-api:2.0.11 -> 2.0.16
| +--- jakarta.xml.bind:jakarta.xml.bind-api:4.0.2
| | \--- jakarta.activation:jakarta.activation-api:2.1.3
| +--- net.minidev:json-smart:2.5.1 (*)
| +--- org.assertj:assertj-core:3.26.3
| | \--- net.bytebuddy:byte-buddy:1.14.18 -> 1.15.11
| +--- org.awaitility:awaitility:4.2.2
| | \--- org.hamcrest:hamcrest:2.1 -> 2.2
| +--- org.hamcrest:hamcrest:2.2
| +--- org.junit.jupiter:junit-jupiter:5.11.4
| | +--- org.junit:junit-bom:5.11.4
| | | +--- org.junit.jupiter:junit-jupiter:5.11.4 (c)
| | | +--- org.junit.jupiter:junit-jupiter-api:5.11.4 (c)
| | | +--- org.junit.jupiter:junit-jupiter-engine:5.11.4 (c)
| | | +--- org.junit.jupiter:junit-jupiter-params:5.11.4 (c)
| | | +--- org.junit.platform:junit-platform-engine:1.11.4 (c)
| | | +--- org.junit.platform:junit-platform-launcher:1.11.4 (c)
| | | \--- org.junit.platform:junit-platform-commons:1.11.4 (c)
| | +--- org.junit.jupiter:junit-jupiter-api:5.11.4
| | | +--- org.junit:junit-bom:5.11.4 (*)
| | | +--- org.opentest4j:opentest4j:1.3.0
| | | \--- org.junit.platform:junit-platform-commons:1.11.4
| | | \--- org.junit:junit-bom:5.11.4 (*)
| | +--- org.junit.jupiter:junit-jupiter-params:5.11.4
| | | +--- org.junit:junit-bom:5.11.4 (*)
| | | \--- org.junit.jupiter:junit-jupiter-api:5.11.4 (*)
| | \--- org.junit.jupiter:junit-jupiter-engine:5.11.4
| | +--- org.junit:junit-bom:5.11.4 (*)
| | +--- org.junit.platform:junit-platform-engine:1.11.4
| | | +--- org.junit:junit-bom:5.11.4 (*)
| | | +--- org.opentest4j:opentest4j:1.3.0
| | | \--- org.junit.platform:junit-platform-commons:1.11.4 (*)
| | \--- org.junit.jupiter:junit-jupiter-api:5.11.4 (*)
| +--- org.mockito:mockito-core:5.14.2
| | +--- net.bytebuddy:byte-buddy:1.15.4 -> 1.15.11
| | +--- net.bytebuddy:byte-buddy-agent:1.15.4 -> 1.15.11
| | \--- org.objenesis:objenesis:3.3
| +--- org.mockito:mockito-junit-jupiter:5.14.2
| | +--- org.mockito:mockito-core:5.14.2 (*)
| | \--- org.junit.jupiter:junit-jupiter-api:5.11.2 -> 5.11.4 (*)
| +--- org.skyscreamer:jsonassert:1.5.3
| | \--- com.vaadin.external.google:android-json:0.0.20131108.vaadin1
| +--- org.springframework:spring-core:6.2.1 (*)
| +--- org.springframework:spring-test:6.2.1 (*)
| \--- org.xmlunit:xmlunit-core:2.10.0
\--- org.junit.platform:junit-platform-launcher -> 1.11.4
+--- org.junit:junit-bom:5.11.4 (*)
\--- org.junit.platform:junit-platform-engine:1.11.4 (*)
(c) - A dependency constraint, not a dependency. The dependency affected by the constraint occurs elsewhere in the tree.
(*) - Indicates repeated occurrences of a transitive dependency subtree. Gradle expands transitive dependency subtrees only once per project; repeat occurrences only display the root of the subtree, followed by this annotation.
A web-based, searchable dependency report is available by adding the --scan option.
BUILD SUCCESSFUL in 3s
1 actionable task: 1 executed
분명 있는데 이새끼이거 뭐야............................................
챗지선생 도와주쇼....
챗지선생에게 물어봤는데, 내게 이것저것 시켜보더니 JUnit5 가 제대로 적용되지 않은거같다며 몇 개 방법을 추천해줬다(의존성은 잘 주입되어있음).
✅ 1️⃣ @BeforeAll은 static 메서드에서만 동작
문제
현재 코드에서는 @BeforeAll을 static 메서드에서 사용하고 있으므로 문제는 없어 보이지만, JUnit 5가 정상적으로 동작하지 않으면 @BeforeAll이 실행되지 않을 수 있음.
해결책
- JUnit 4의 @BeforeClass를 import하지 않았는지 확인
- import org.junit.BeforeClass;가 있으면 안 됨. (JUnit 4용)
- JUnit 5에서는 @BeforeClass가 존재하지 않음 → @BeforeAll만 사용 가능
- JUnit 5가 정상적으로 실행되고 있는지 확인
- @Test를 추가하여 테스트 실행이 되는지 확인
- @BeforeAll 메서드가 실행되지 않으면 JUnit 5가 정상적으로 동작하지 않을 가능성이 높음
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class BookValidationTests {
private static Validator validator;
@BeforeAll
static void setUp() {
System.out.println("BeforeAll 실행됨!"); // ✅ 실행 확인을 위한 로그 추가
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
void testDummy() {
System.out.println("테스트 실행됨!"); // ✅ JUnit 5 실행 확인
}
}
ㅎㅎ.....
C:\Y\Cloud Native Spring in Action\catalog-service>gradlew.bat test --tests com.polarbookshop.catalogservice.domain.BookValidationTests
> Task :compileJava
C:\Y\Cloud Native Spring in Action\catalog-service\src\main\java\com\polarbookshop\catalogservice\domain\BookValidationTests.java:6: error: package org.junit.jupiter.api does not exist
import org.junit.jupiter.api.BeforeAll;
^
C:\Y\Cloud Native Spring in Action\catalog-service\src\main\java\com\polarbookshop\catalogservice\domain\BookValidationTests.java:12: error: cannot find symbol
@BeforeAll
^
symbol: class BeforeAll
location: class BookValidationTests
C:\Y\Cloud Native Spring in Action\catalog-service\src\main\java\com\polarbookshop\catalogservice\domain\BookValidationTests.java:19: error: cannot find symbol
@Test
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler output below.
C:\Y\Cloud Native Spring in Action\catalog-service\src\main\java\com\polarbookshop\catalogservice\domain\BookValidationTests.java:6: error: package org.junit.jupiter.api does not exist
import org.junit.jupiter.api.BeforeAll;
^
C:\Y\Cloud Native Spring in Action\catalog-service\src\main\java\com\polarbookshop\catalogservice\domain\BookValidationTests.java:12: error: cannot find symbol
@BeforeAll
^
symbol: class BeforeAll
location: class BookValidationTests
C:\Y\Cloud Native Spring in Action\catalog-service\src\main\java\com\polarbookshop\catalogservice\domain\BookValidationTests.java:19: error: cannot find symbol
@Test
^
symbol: class Test
location: class BookValidationTests
3 errors
* Try:
> Check your code and dependencies to fix the compilation error(s)
> Run with --scan to get full insights.
BUILD FAILED in 7s
1 actionable task: 1 executed
안됨ㅎㅎ........
❌ JUnit 패키지를 찾을 수 없는 문제 해결 (JUnit 라이브러리 누락)
📌 org.junit.jupiter.api.BeforeAll을 찾을 수 없다는 에러는 JUnit 5 라이브러리가 프로젝트에 제대로 추가되지 않았기 때문입니다.
또한 @Test 어노테이션도 찾을 수 없다는 점에서, 전체적인 JUnit 5 설정이 안 되어 있을 가능성이 큽니다.
✅ 🔹 해결 방법
1️⃣ testImplementation을 다시 추가
📌 JUnit 5가 build.gradle에 제대로 포함되어 있는지 확인하세요.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
// JUnit 5 테스트 의존성
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// JUnit 5 추가 라이브러리 (필요할 경우)
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
}
tasks.named('test') {
useJUnitPlatform()
}
📌 testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3' 추가하면 더 확실합니다.
(스프링 부트 3.4.1의 기본 spring-boot-starter-test에는 JUnit 5가 포함되어 있지만, 직접 추가하는 것이 더 안정적입니다.)
2️⃣ gradlew clean build 실행 후 다시 테스트
라이브러리 캐시를 지우고 다시 빌드해보세요.
gradlew.bat clean build
📌 이후 다시 실행
gradlew.bat test --tests com.polarbookshop.catalogservice.domain.BookValidationTests
여기까지했을때.... 문제를 알아차렸다, 내가 이 클래스 파일을 main에 만들어버림.test로 옮겨서 실행하니 잘됨 ^^...오늘 또 뻘짓했다 휴
gradlew.bat test --info 로 로깅해둔 거 찍히는 지 확인
package com.polarbookshop.catalogservice.domain;
import jakarta.validation.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Set;
//Book 객체의 유효성 검사 제약조건을 검증하기 위한 단위 테스트
public class BookValidationTests {
private static Validator validator;
// @BeforeAll: 클래스 내의 테스트를 실행하기 전에 가장 먼저 실행할 코드 블록임을 나타냄.
@BeforeAll
static void setUp() {
System.out.println("BeforeAll 실행됨!");
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test // 테스트 케이스임을 나타냄
void whenAllFieldsCorrectThenValidationSucceeds() {
System.out.println("정상 데이터 테스트 케이스 실행");
var book = new Book("0104567890", "제목쏼라쏼라", "김작가",9.80);
Set<ConstraintViolation<Book>> violations = validator.validate(book);
assertThat(violations).isEmpty(); // 유효성 검사에서 오류 없음 확인
}
@Test // 테스트 케이스임을 나타냄
void whenIsbnDefinedIncorrectThenValidationFails() {
System.out.println("비정상 데이터 테스트 케이스 실행");
// 유효하지않은 ISBN 입력
var book = new Book("ab45678d90", "제목쏼라", "정작가",8.70);
// book 객체의 유효성을 검사하고, 제약 조건을 위반한 항목들을 Set<ConstraintViolation<Book>>에 저장.
Set<ConstraintViolation<Book>> violations = validator.validate(book);
// 오류가 1개인지 확인
assertThat(violations).hasSize(1);
// 만약 getMessage()의 실제 값이 "The book ISBN must be defined"이면, 테스트는 실패
assertThat(violations.iterator().next().getMessage()).isEqualTo("The ISBN format must be valid.");
}
}
최종소스.
돌려본다...!
ㅋ
ㅋ
ㅋ
ㅋ
점찍어서 테스트 실패함 ㅅㅂ ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
암튼 점지우니 성공 ^^.....이야...... 절겁다.....
+ 추가 지식
📌 ConstraintViolation<T>란?
ConstraintViolation<T>는 Jakarta Validation API에서 제공하는 인터페이스로, 유효성 검사(Validation)에서 발생한 오류 정보를 저장하는 객체입니다.
즉, 어떤 필드가 어떤 이유로 제약 조건을 위반했는지에 대한 정보를 담고 있음.
기본 개념
- T는 유효성 검사를 실행한 객체의 타입을 나타냅니다.
- ConstraintViolation<T> 객체는 다음 정보를 포함합니다.
- 어떤 필드에서 오류가 발생했는지 (getPropertyPath())
- 어떤 제약 조건이 위반되었는지 (getConstraintDescriptor())
- 실제 입력 값이 무엇인지 (getInvalidValue())
- 오류 메시지가 무엇인지 (getMessage())
'Cloud Native Spring in Action' 카테고리의 다른 글
@WebMvcTest를 사용한 REST 컨트롤러 테스트 (0) | 2025.02.10 |
---|---|
@SpringBootTest 를 통한 통합 테스트 (0) | 2025.02.10 |
중앙식 예외 핸들러와 이를 이용한 오류 처리 (0) | 2025.02.06 |
데이터 유효성 검사 (1) | 2025.02.06 |
스프링 MVC를 이용한 REST API 구현, 그리고 Httpie 설치와의 사투 (0) | 2025.02.06 |