Hyeonuk_.log

[Junit5] @BeforeAll를 사용하다...멘붕...(토비스프링 읽다가) 본문

Dev_.log/Spring

[Junit5] @BeforeAll를 사용하다...멘붕...(토비스프링 읽다가)

Hyeonuk_. 2022. 3. 6. 17:01

요즘 토비의 스프링을 다시 읽고 있다.

두번째 읽고 있는 것인데 첫번째 읽을 때보다 이해도 잘되고 더 얻어가는게 많다.

2장을 읽고 있는데 2장의 소스코드를 따라서 작성해보다가 오류가 났던 것을 적어두려한다.

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = DaoFactory.class)
public class UserDaoTest {
	
	@Autowired
	private static ApplicationContext applicationContext;
	
	private static UserDao userDao;
	private static User user1;
	private static User user2;
	private static User user3;
	
	@BeforeAll
	public void setUp() {
		
		userDao = applicationContext.getBean("userDao", UserDao.class);
		
		user1 = new User("1","test1","test");
		user2 = new User("2","test2","test");
		user3 = new User("3","test3","test");
	}
	
	@Test
	@DisplayName("addAndGet")
	public void addAndGet() throws SQLException {
		
		userDao.deleteAll();
		assertEquals(userDao.getCount(), 0);
		
		User user = new User();
		user.setId("1");
		user.setName("test");
		user.setPassword("test");
		
		userDao.add(user);
		assertEquals(userDao.getCount(), 1);
		
		User user2 = userDao.get(user.getId());
		
		assertEquals(user2.getName(), user.getName());
		assertEquals(user2.getPassword(), user.getPassword());
		
	}
	
	@Test
	@DisplayName("getUserFail")
	public void getUserFail() throws SQLException {
		
		userDao.deleteAll();
		assertEquals(userDao.getCount(), 0);
		
		User user = new User();
		user.setId("1");
		user.setName("test");
		user.setPassword("test");
		
		assertThrows(EmptyResultDataAccessException.class, () -> {
			userDao.get(user.getId());
        });
		
		
	}

}

 

처음에는 아무런 문제가 없는 줄 알았다... 그냥 테스트 전에 테스트에 필요한 픽스처를 셋팅하고 테스트가 진해되겠거니...생각했다...

그러나

@BeforeAll은 Junit4에서 @BeforeClass와 동일하며 변수와 메소드가 static으로 선언되어야한다. static으로 선언이 되면 클래스가 로드되기전에 로드가 된다.
따라서 클래스가 로드되어야 @ExtendWith(SpringExtension.class),  @ContextConfiguration(classes = DaoFactory.class) 이 두가지 설정을 보고 ApplicationContext가 가져와질텐데 로드되기 전에 빈을 가져오려고 하다보니 NullPointException이 발생했다.

그래서 @BeforeAll 대신해서 @BeforeEach로 변경했다. 책에서도 @Before을 사용했다(Junit4에서 @Before와 Junit5에서 @BeforeEach같다.)

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = DaoFactory.class)
public class UserDaoTest {
	
	@Autowired
	private ApplicationContext applicationContext;
	
	private UserDao userDao;
	private User user1;
	private User user2;
	private User user3;
	
	@BeforeEach
	public void setUp() {
		System.out.println(this.applicationContext);
		System.out.println(this);
		
		userDao = applicationContext.getBean("userDao", UserDao.class);
		
		user1 = new User("1","test1","test");
		user2 = new User("2","test2","test");
		user3 = new User("3","test3","test");
	}
	
	@Test
	@DisplayName("addAndGet")
	public void addAndGet() throws SQLException {
		
		userDao.deleteAll();
		assertEquals(userDao.getCount(), 0);
		
		User user = new User();
		user.setId("1");
		user.setName("test");
		user.setPassword("test");
		
		userDao.add(user);
		assertEquals(userDao.getCount(), 1);
		
		User user2 = userDao.get(user.getId());
		
		assertEquals(user2.getName(), user.getName());
		assertEquals(user2.getPassword(), user.getPassword());
		
	}
	
	@Test
	@DisplayName("getUserFail")
	public void getUserFail() throws SQLException {
		
		userDao.deleteAll();
		assertEquals(userDao.getCount(), 0);
		
		User user = new User();
		user.setId("1");
		user.setName("test");
		user.setPassword("test");
		
		assertThrows(EmptyResultDataAccessException.class, () -> {
			userDao.get(user.getId());
        });
		
		
	}

}

 

추가적으로 System.out.println(this.applicationContext);와  System.out.println(this);를 찍어봤다. 결과는

ApplicationContext는 2번 모두 동일하고 UserDaoTest는 2번 모두 다른 오브젝트 주소를 갖는다. Junit은 테스트 메소드를 실행할 때마다 새로운 테스트 오브젝트를 만들기 때문이다. 또한 타 테스트 클래스에서 @ContextConfiguration(classes = DaoFactory.class)를 동일하게 사용할 경우, 하나의 ApplicationContext가 공유된다.

매번 새로운 오브젝트를 만들고 있는지 한번 진짜 테스트를 해보자.

public class JUnitTest {
	
	static Set<JUnitTest> testObjects = new HashSet<JUnitTest>();
	
	@Test
	public void test1() {
		assertThat(testObjects, not(hasItem(this)));
		testObjects.add(this);
	}
	
	@Test
	public void test2() {
		assertThat(testObjects, not(hasItem(this)));
		testObjects.add(this);
	}
	
	@Test
	public void test3() {
		assertThat(testObjects, not(hasItem(this)));
		testObjects.add(this);
	}

}

모두 성공한다. 매번 새로운 오브젝트를 만든다는 것을 알 수 있다.

 

참고
https://junit.org/junit5/docs/5.0.0/user-guide/#writing-tests-annotations

Comments