패키지 의존성 테스트
간단한 글, 댓글, 유저만 있는 CRUD를 만들때도 모두 양방향 연관관계 맵핑 이후에 DTO로 만들 때 순환참조를 막았었는데 서비스에 필요한 단방향 연관관계만으로 이런 과정을 생략할 수 있다.
단방향으로 참조를 하고 있는지 확인 할 수 있는 ArchUnit 라이브러리를 사용해 패키지 간 의존성 참조받는 것과 하는 것, 순환참조 여부를 눈이 아니라 테스트 코드로 확인할 수 있다.
기준 버젼은 자바 17, 스프링부트 2.7.11 이다.
gradle
testImplementation group: 'com.tngtech.archunit', name: 'archunit-junit5', version: '0.13.1'
code
public class PackageDependencyTests {
private static final String TEAM = "..modules.team..";
private static final String EVENT = "..modules.event..";
private static final String ACCOUNT = "..modules.account..";
private static final String TAG = "..modules.tag..";
private static final String ZONE = "..modules.zone..";
JavaClasses jc = new ClassFileImporter()
.importPackages("com.guham.guham..");
@Test
public void teamPackageRuleCheck(){
ArchRule teamPackageRule = classes().that().resideInAPackage(TEAM)
.should().onlyBeAccessed()
.byClassesThat().resideInAnyPackage(TEAM, EVENT); // 팀 패키지 참조 당하는 곳 체크
teamPackageRule.check(jc);
}
@Test
public void eventPackageRuleCheck(){
ArchRule eventPackageRule = classes().that().resideInAPackage(EVENT)
.should().accessClassesThat()
.resideInAnyPackage(TEAM,ACCOUNT, EVENT); // 이벤트 패키지가 참조 하는 곳 체크
eventPackageRule.check(jc);
}
@Test
public void accountPackageRuleCheck(){
ArchRule accountPackageRule = classes().that().resideInAPackage(ACCOUNT)
.should().accessClassesThat()
.resideInAnyPackage(ACCOUNT, ZONE, TAG); // 계정 패키지가 참조하는 곳 체크
accountPackageRule.check(jc);
}
@Test
public void test(){
ArchRule matching = slices().matching("com.guham.guham.modules.(*)..") // 루트 패키지 내에 순환참조 체크
.should().beFreeOfCycles();
matching.check(jc);
}
}
테스트 오류가 발생하는 클래스를 토대로 패키지 이동을 시켜주고, 필요하다면 코드를 변경한다.
TestContainers
스프링부트를 이용한 테스트 시에는 별도의 애플리케이션 설정을 건드리지 않으면 디폴트인 메모리 H2를 사용한다. 별도의 테스트용 DB를 사용하면 좋지만 관리 포인트 및 비용이 늘어나므로 테스트 시에만 로컬에 설치된 도커를 이용해 데이터베이스를 띄워이용하기 위해 TestContainers를 사용한다. 기존 애플리케이션 사용시 MySQL을 사용해 테스트컨테이너도 MySQL를 사용한다.
로컬에 도커가 꼭 실행되야 한다.
gradle
testImplementation "org.testcontainers:testcontainers:1.18.1"
testImplementation "org.testcontainers:mysql:1.18.1"
test.resources.application.yml
spring:
jpa:
hibernate:
ddl-auto: update
datasource:
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
url: jdbc:tc:mysql:8://testdb
driver-class는 사용하는 testcontainerDB에 따라 달라진다. url은 테스트컨테이너 사용시 tc로 호스트를 대신할 수 있고, 데이터베이스 스키마는 임의로 설정하면 된다.
테스트 컨테이너 띄우기
abstract public class AbstractContainerTest {
static final MySQLContainer MY_SQL_CONTAINER;
static{
MY_SQL_CONTAINER = new MySQLContainer("mysql:8");
MY_SQL_CONTAINER.start();
}
}
모든 테스트에서 사용할 수 있게 static 필드로 사용하고 static 블록으로 초기화 및 해당 추상 클래스를 테스트 클래스에서 상속받아 사용한다.
테스트 클래스 상속
@MockMVCTest
class AccountControllerTest extends AbstractContainerTest {
테스트 컨테이너를 띄워주는 추상클래스를 상속받으면 클래스 내의 테스트 메소드는 모두 테스트 컨테이너에서 작동한다.
참고
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-JPA-
https://www.baeldung.com/java-archunit-intro