Spring을 사용하면 테스트에 대한 접근이 상당히 쉬워진다.
JUnit5를 연습하자는 마음으로 시작했다.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
빌드 툴은 Maven을 사용했으며 버전은 5.7.0을 사용한다.
Spring 버전은 4.1.0.RELEASE를 사용하기로 했다.
이 내용은 토비의 스프링을 참고하여 작성하였다.
package test;
import com.test.test.domain.Configuration;
import com.test.test.domain.User;
import com.test.test.domain.UserDao;
import org.junit.jupiter.api.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.dao.EmptyResultDataAccessException;
import java.sql.SQLException;
import static org.junit.jupiter.api.Assertions.*;
public class UserDaoTest {
@Test
void count() throws SQLException {
ApplicationContext ac =new AnnotationConfigApplicationContext(Configuration.class);
UserDao dao = ac.getBean("userDao",UserDao.class);
User user = new User("gyumm","박상철", "springNo1");
User user2 = new User("lee","노홍철", "secret");
User user3 = new User("sung","성일","pwd");
dao.deleteAll();
assertEquals(dao.getCount(),0);
dao.add(user);
assertEquals(dao.getCount(),1);
dao.add(user2);
assertEquals(dao.getCount(),2);
dao.add(user3);
assertEquals(dao.getCount(),3);
}
@Test
public void addAndGet() throws SQLException, ClassNotFoundException {
ApplicationContext context = new AnnotationConfigApplicationContext(Configuration.class);
UserDao dao = context.getBean("userDao", UserDao.class);
dao.deleteAll();
assertEquals(dao.getCount(),0);
User user = new User("gyumee", "박상철", "springno1");
User user2 = new User("leegw700","이길원","springno2");
dao.add(user);
dao.add(user2);
assertEquals(dao.getCount(),2);
User userget1 = dao.get(user.getId());
assertAll(
() -> assertEquals(userget1.getName(), user.getName()),
()-> assertEquals(userget1.getPassword(),user.getPassword())
);
User userget2 = dao.get(user2.getId());
assertAll(
() -> assertEquals(userget2.getName(), user2.getName()),
()-> assertEquals(userget2.getPassword(),user2.getPassword())
);
}
@Test
void getUserFailure() throws SQLException {
ApplicationContext ac = new AnnotationConfigApplicationContext(Configuration.class);
UserDao dao = ac.getBean("userDao",UserDao.class);
dao.deleteAll();
assertEquals(dao.getCount(),0);
assertThrows(EmptyResultDataAccessException.class,()->{
dao.get("unknown_id");
});
}
}
테스트 케이스를 만들다 보니 반복되는 것들이 보인다. 애플리케이션 콘텍스트를 생성하는 부분과 해당 콘텍스트의 에 UserDao를 가져오는 부분이 보인다.
나는 중복된 다면 보통 메서드로 뽑아내는데 몇 줄 안 되는 코드는 그냥 중복하기도 한다. 여기서는 JUnit이 제공하는 기능을 활용한다고 한다.
@BeforEach를 사용하여 각 각의 테스트 케이스가 실행하기 전에 반복적으로 실행되는 코드를 축약할 수 있다고 한다.
private UserDao dao;
@BeforeEach
void setUp(){
ApplicationContext ac =new AnnotationConfigApplicationContext(Configuration.class);
this.dao = ac.getBean("userDao",UserDao.class);
}
JUnit는 다음과 같이 동작한다고 한다.
1. @Test , public , void 파라미터가 없는 테스트 메서드를 수집
2. 테스트 클래스의 오브젝트 생성
3. @BeforEach가 붙은 메서드 있다면 실행
4. @Test 메서드 호출한 뒤 결과 저장해둔다.
5. @After 메소드 실행
6. 2~5번 반복
7. 모든 테스트의 결과 종합해서 반환
다만 @Before ,@After 메서드를 직접 호출하지 않기 때문에 주고받을 오브젝트에 대해서는 인스턴스 변수를 사용한다고 한다. 만약 이렇게 사용되는 오브젝트가 무겁다면? 그래서 Mock을 사용하는 건가?
부분적으로 공통되는 코드는 차라리 메서드 추출 방법을 사용해 호출하는 것이 낫다고 한다. 혹은 동일 설정을 가진 테스트만 모아서 만드는 것도 다른 방법이라고 한다.
테스트를 수행하는 데 필요한 정보나 오브젝트를 픽스처 fixture라고 한다. 구글링 할 때 참고할만한 단어이다.
위의 코드에서는 dao가 대표적인 픽스처이다. 혹은 User 오브젝트도 픽스처가 할 수 있다고 한다.
여기서는 애플리케이션 컨텍스트는 3번 만들어지는데, 사실 이러한 콘텍스트는 하나만 만들고 공유하는 것이 바람직하다. 빈은 싱글톤으로 만들어지기 때문에 특정한 상태를 갖지는 않고 콘텍스트 상태도 고정일 테고 db상태는 각 테스트에서 초기화하기 때문에 상관없다.
이에 대한 답은 여러 개가 있지만 JUnit5에서 제공하는 딱 한번 실행하는 static 메서드인 @BeforeAll을 사용하거나 스프링이 제공하는 애플리케이션 콘텍스트 테스트 지원 기능이 있다고 한다.
ExtendWith(SpringExtension.class)인데 스프링 4에는 없어서 스프링 5로 올렸다..
또한 springframework-test도 종속성을 받았다.
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = Configuration.class)
public class UserDaoTest {
@Autowired
private ApplicationContext ac;
다음과 같은 코드로 처리해서 테스트에 성공했다 이것은 Spring TextConext Framework를 JUnit5의 Jupiter 프로그래밍 모델에 통합한다고 한다. 공식문서 참조했다.
저 @Autowired는 테스트 객체가 만들어 질때 스프링 테스트 콘텍스트가 자동으로 콘텍스트 객체를 주입해준다.
'Test' 카테고리의 다른 글
| TDD 시작 (0) | 2022.12.10 |
|---|---|
| JUnit (0) | 2022.11.08 |
| 데이터베이스 연동 테스트 (0) | 2022.10.14 |
| JUnit5 (2) (0) | 2021.03.14 |
| Test (0) | 2021.03.14 |
댓글