DevBoi

[Test Code] Spock Framework + TestContainers 본문

Develop/[Test Code]

[Test Code] Spock Framework + TestContainers

HiSmith 2023. 4. 24. 00:05
반응형

우선 프로젝트에서는 간단하게 JPA로 insert, delete,select하는 게 있다고 가정하자.

구조만 보이면, 어느정도 동작에 대해서는 알것이라고 기억이 날 것이라고 생각이 된다.

이제 테스트 코드를 작성해보자

우선 Spock를 위해서는 2가지 gradle상 추가를 해야한다.

 

1) 의존성 추가 + 플러그인 추가

 

2) 기본 Spock 사용

총 6단계로 나뉜다. 각 feature 메소드라고 부른다.

setup,when,then,expect,cleanup,where

 

1) given,when,then 3가지 기본 사용법

2) Spring Boot Test

2-1) 컨텍스트에 빈 존재유무 테스트

뭔가 구리고 더럽다, 간단하게 바꾸자

 

2-2) 해당 서비스의 값이 올바른지 확인

사실 2-1을 했으면 거저 먹기인데, 정상적으로 서비스의 로직의 return값이 체크되는것이다.

정상적으로 주입을 받았고, 값을 가져오는지 정도를 체크하는것이다.

 

2-3) 데이터 insert 테스트

근데 이러면 문제가 있다.

테스트를 실행했는데, 데이터가 들어가 있게 되는것이다.

원래 같은경우에는 별도로 디비를 두거나, 트랜잭션단위로 데이터를 날리거나

테스트컨테이너를 쓰는게 정상적이다만, 우선 이번 포스팅은 Spock에 초점을 두므로

2-4를 해본다. 테스트 컨테이너의 내용은 더 밑에서 다룰 예정이다.

 

2-4) 데이터 세팅 및 초기화하기

이렇게 세팅 및 초기화를 할수 있다고하는데..

너무 귀찮지 않나...?

일단 구현하고, 트랜잭션단위로 날려주는걸 찾아보자

일단 이렇게 하면, 생성 + 체크 + 원복이 된다.

근데, Junit에 비해서 공통으로 뭔가 트랜잭션 분리가 어려워보인다.

좀더 간편한 방법을 찾아보자

 

2-5) where 절 사용

 

where 절을 사용하면, 여러개의 테스트 데이터를 진행해볼 수 있다.

 

 

 

3-1) 테스트 컨테이너 사용

테스트 컨테이너를 사용해서, 테스트 코드 구동시에 테스트 컨테이너를 생성하고

그다음에 테스트 코드가 종료되면 컨테이너가 삭제 되게끔 구성을 해보자

일단 아래와 같은 조건이 있다.

1. 테스트 컨테이너가 static 해야함

2. 테스트 컨테이너의 정보를 생성하고 올려서 테스트 빌드 후 삭제가 되어야함

 

그래서 아래와 같이 구현했다.

결론은 간단하지만 시행착오가 많았다.

참고로 Window wsl 에서 구현했다.

 

1) Gradle impl

 

2) Testcontainer 구동시 생성되는 .testcontainer.properties

위 내용은, 도커 데몬의 위치를 알려준다.

즉, 도커 데몬을 표기 해놓으면, 해당 위치에 데몬에게 컨테이너를 생성해! 라고하는것이다.

 

3) ApplicationContextInitalizer

 

이게 필요한 이유는 테스트 코드에서 mapper 빈을 의존성 주입을 받는데,

컨테이너 생성시점은 그 이후이기 떄문이다.

즉, context -> 컨테이너 생성 -> mapper사용

이때 mapper는 context에서 생성된, 데이터베이스 정보 즉 config 파일에 있는 디비정보를 기반으로

Datasource 빈을 생성한다.

그래서 컨테이너 생성 이후에, 테스트 빏드시, datasource에서 사용하는, 몇개의 빈을 override해주어야

테스트 컨테이너의 정보로 디비 호출이된다.

 

3) Test container staic 

여러개의 테스트 코드를 사용할때,

테스트 코드에서 container start를 하거나 각각 선언하게 되면

테스트 코드 클래스 개수 만큼 컨테이너가 생성이 된다.

이는 실무 다른 서비스에 영향이 갈 수도 있고, 오히려 더 많은 시간이 걸리게 된다.

개인적으로는 static 하지 않게 쓰는 이유가 테스트코드 클래스 1개 이외인경우에는 왜 쓰는지 모르겠다.

더 비효율적이라고 생각한다.

 

4) 테스트 코드 작성

 

testService 나 a class의 내용은 실무단 클래스명을 노출 할 수 없어서, 이렇게 표기했다.

무튼, SpringbootTest에서는 메인 클래스를 작성해주면 되고

Initalizer에서는 아까 작성한 이니셜 라이저

그리고 서비스를 의존 받아서 사용하면, 정상적으로 테스트 컨테이너로의 호출 및 디비 작업이 가능해진다.

 

etc) Spock 지식

 

1) where 절에서는 여러개의 테스트 데이터를 넣어볼수 있다.

2) void문을 테스트 하고 싶을때는 then: 절에 noexpectThorwn()을 사용하면 된다.

3) given: when: then:을 사용하지만, when, then을 합친 expect도 깔끔하다

4) 여러 테스트 메소드, 피처 메소드에서 공유하는 변수는 @Shared로 표기하여, 사용할 수 있다.

 

 

 

끗-

반응형

'Develop > [Test Code]' 카테고리의 다른 글

[Junit] Test coverage 확인하기_Jacoco  (0) 2022.04.27
[Springboot]Springboot_test  (0) 2022.04.26