테스트를 왜하는 걸까?
junit 사용 전에 main에서 테스트를 했었는데 이는 많은 문제가 있었다. 구현코드와 테스트 코드가 하나의 클래스에 있으면서 클래스 크기가 커지고, 테스트코드가 서비스에 배포될 수도 있고, 메인 함수에 여러 기능이 담겨져 있을 수도 있는 것 등 많은 문제들을 동반할 수 밖에 없다. 이러한 문제를 보완하기 위해 junit을 통한 테스트 공간이 만들어졌다.
Junit 기본 애노테이션은 무엇이 있을까?
테스트 메소드 annotation
1.
@Test : 테스트 메서드 선언
2.
@DisplayName(”붙이고 싶은 이름”) : 테스트에 이름을 붙여준다.
3.
@ExtendWith : extension을 등록하며, 이 어노테이션은 상속이 된다. 확장팩이라고 생각하면 될 것 같다.
라이프 사이클 annotation
1.
@BeforeEach : 각각 테스트 메소드가 실행되기전에 실행되어야 하는 메소드를 명시해준다.
@Test, @RepeatedTest , @ParameterizedTest, @TestFactory 가 붙은 테스트 메소드가 실행하기 전에 실행된다.
2.
@AfterEach : @Test, @RepeatedTest , @ParameterizedTest, @TestFactory 가 붙은 테스트 메소드가 실행되고 난 후 실행된다.
@ContextConfiguration은 무엇인가?
TestContext를 로딩하기 위한 Test Configuaration은 다음과 같은 우선순위를 가진다.
1.
@ContextConfiguration 또는 @ContextHierarchy(여러 @ContextConfiguration을 포함)
2.
Nested @Configuration
3.
@SpringBootConfiguration (@SpringBootApplication 어노테이션이 @SpringBootConfiguration 어노테이션을 포함하고 있음)
4.
Nested @TestConfiguration
1, 2, 3번은 하나는 필수이며, 이 중 하나만 적용된다
At its core, the TestContext framework allows you to annotate test classes with @ContextConfiguration to specify which configuration files to use to load the ApplicationContext for your test.
https://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles
@ContextConfiguration 어노테이션에 기술한 file들이 ApplicationContext에 로딩되는 것을 TestContext framework에서 해준다는 내용이다. ㅇ_ㅇ?
@ContextConfiguration(classes = UserDaoFactory.class) 이렇게 되어 있을 경우 UserDaoFactory 클래스에 있는 bean들을 읽어와 테스트할 수 있게 해준다는 것 같다.
UserDaoFactory는 빈을 생성, 관리 등을 해주는 역할로 만들어져 있다
적용해보기
테스트를 확인할 메서드는 다양하게 있지만 assertEqulas(예상되는 값, 로직)과 assertThrows(예외클래스, 함수) 를 사용할 것이다.
1. 테스트 설정해두기
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = UserDaoFactory.class)
class UserDaoTest {
UserDao userDao;
@Autowired
ApplicationContext context;
}
Java
복사
SpringExtension으로 확장하고 UserDaoFacotry.class에 있는 빈들을 테스트하고 싶다. userDao 오브젝트를 선언해놓고, ApplicationContext를 @Autowired를 통해 주입받는다. ( @Autowired를 필드에서 주입하는 것은 테스트상황이기에 해둔 것이며, 테스트 방법 외에는 이러한 의존성 주입은 지양하는 것이 좋다.) 그럼 “ApplicationContext” 얘는 어떤 역할을 할까? ApplicationContext은 스프링 컨테이너라고 불리며 스프링 빈을 관리하고 조회하는 역할을 한다.
2. @BeforeEach
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = UserDaoFactory.class)
class UserDaoTest {
UserDao userDao;
@Autowired
ApplicationContext context;
@BeforeEach
void setUp() {
this.userDao = context.getBean("awsUserDao", UserDao.class);
userDao.deleteAll();
userDao.add(new User("100", "homidle", "1234"));
assertEquals(1, userDao.getCount());
}
}
Java
복사
앞서 설명했듯이 @BeforeEach는 각각 테스트가 실행되기 전에 사전실행이 되는 것이다. 각각의 테스트들은 다른 테스트에 영향을 받지 않게하기위해 데이터베이스의 users의 칼럼들을 모두 지우고, 새로운 유저 1명만 생성해 두고 싶어서 이렇게 코드를 짰다.
3. AddAndSelect
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = UserDaoFactory.class)
class UserDaoTest {
UserDao userDao;
@Autowired
ApplicationContext context;
@BeforeEach
void setUp() {
this.userDao = context.getBean("awsUserDao", UserDao.class);
userDao.deleteAll();
userDao.add(new User("100", "homidle", "1234"));
assertEquals(1, userDao.getCount());
}
@Test
void addAndSelect() {
User user = new User("11", "IVE", "1234");
userDao.add(user);
User findUser = userDao.findById("11");
assertEquals("IVE", findUser.getName());
}
}
Java
복사
userDao의 add()은 데이터를 저장하는 역할을 한다. findById()는 유저의 아이디를 통해 그 사람의 정보를 알고 싶은 것이다.
4. count
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = UserDaoFactory.class)
class UserDaoTest {
UserDao userDao;
@Autowired
ApplicationContext context;
@BeforeEach
void setUp() {
this.userDao = context.getBean("awsUserDao", UserDao.class);
userDao.deleteAll();
userDao.add(new User("100", "homidle", "1234"));
assertEquals(1, userDao.getCount());
}
@Test
void count() {
userDao.deleteAll();
assertEquals(0, userDao.getCount());
User user1 = new User("1", "Chin", "20");
User user2 = new User("2", "Ck", "21");
User user3 = new User("3", "Louie", "22");
userDao.add(user1);
assertEquals(1, userDao.getCount());
userDao.add(user2);
assertEquals(2, userDao.getCount());
userDao.add(user3);
assertEquals(3, userDao.getCount());
}
}
Java
복사
getCount() 로직을 확인하기 위해 만들었다. 아까 @Beforeach에서 유저객체 1개를 만들어 두었기 때문에, 모든 데이터를 지우면 개수가 0이고, 각각의 유저가 추가될때 +1을해주어 개수를 파악하는 것이다.
5. findByIdEmpty
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = UserDaoFactory.class)
class UserDaoTest {
UserDao userDao;
@Autowired
ApplicationContext context;
@BeforeEach
void setUp() {
this.userDao = context.getBean("awsUserDao", UserDao.class);
userDao.deleteAll();
userDao.add(new User("100", "homidle", "1234"));
assertEquals(1, userDao.getCount());
}
@Test
void findByIdEmpty() {
assertThrows(RuntimeException.class, () -> {
userDao.findById("1000");
});
}
}
Java
복사
존재하지 않는 값의 id을 찾으면 당연히 오류가 뜬다. 예외처리에서 RuntimeException을 던지도록 해놓았기에 오류클래스를 RuntimeException.class를 두었고, 람다함수를 통해 1000번 아이디를 가진 유저가 있으면 오류가 뜨도록 하였다.