싸피 스프링 과제 중 Junit 테스트를 하는데, 자꾸 NoSuchBeanDefinitionException라는 에러가 발생했다. 설정은 분명 제대로 했는데 도대체 왜 안되는지 몰라서 한참을 해멨는데, 이 에러에 대한 해답을 알고나니 너무 바보같았다 ㅠ
   그림 1) root-context.xml 파일
  그림 1) root-context.xml 파일
프로젝트의 root-context.xml 파일이다.
dataSource라는 빈이 있는데, 이 빈은 JndiObjectFactoryBean이라는 클래스를 스프링 컨테이너에 등록한다. 그런데 나는 아무 생각 없이 DataSource라는 이름으로 등록되었다는 이유만으로 DataSource 클래스에 이 빈을 주입시키려는 바보같은 짓을 했다,,,,
   그림 2) 테스트 코드
  그림 2) 테스트 코드
위의 코드가 테스트 코드이다. DataSource는 빈으로 등록되어있지 않았는데, @Autowired로 등록하려고 해서 벌어진 예외 상황이었다. 원래 쓰려고 했던 클래스는 SqlSession이었으므로 DataSource 클래스 대신 SqlSession으로 변경하니 이 예외는 사라졌다.
하지만 저거를 고치고 나니 새로운 에러가 터져버렸다...
이 예외는 JNDI가 초기화에 실패해서 발생하는 예외이다. 오류 로그는 다음과 같이 발생했다.
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or in an application resource file: java.naming.factory.initial
	at java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:702)
	at java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
	at java.naming/javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:342)
	at java.naming/javax.naming.InitialContext.lookup(InitialContext.java:409)
	at org.springframework.jndi.JndiTemplate.lambda$lookup$0(JndiTemplate.java:157)
	at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:92)
	at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:157)
	at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:179)
	at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:96)
	at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:114)
	at org.springframework.jndi.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:239)
	at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:225)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)이거에 대해서 구글링을 해보니 JNDI는 WAS에 설정 정보가 있고, WAS를 켰을 때 그에 대한 정보를 읽는다고 하는데 JUnit은 WAS 없이 테스트하기 때문에 JNDI가 초기화되지 않아서 발생하는 것 같다. 실제로 WAS를 켜서 실제 서비스에서 DB 연동이 되는지 확인해보니 제대로 작동하는 걸 확인할 수 있었다.
   그림 3) 실제 서비스 환경
  그림 3) 실제 서비스 환경
JUnit 테스트 환경은 WAS와 별개이고 여기에서 JNDI를 사용하기 위해서는 따로 설정을 해줘야 한다는 말이다.
그 설정은 다음과 같다.
package com.ssafy.ws;
import org.junit.runners.model.InitializationError;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jndi.JndiTemplate;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class TestSpringRunner extends SpringJUnit4ClassRunner {
	public TestSpringRunner(Class<?> clazz) throws InitializationError {
		super(clazz);
		try {
        bindJndi();
    } catch (Exception e) {
        
    }
	}
	@SuppressWarnings("deprecation")
	private void bindJndi() throws Exception {
        SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
        builder.activate();
        
        JndiTemplate jndiTemplate = new JndiTemplate();
        
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/ssafydb?useSSL=false&serverTimezone=UTC");
        dataSource.setUsername("ssafy");
        dataSource.setPassword("ssafy");
        
        jndiTemplate.bind("java:comp/env/jdbc/ssafy", dataSource);
    }
}SpringJUnit4ClassRunner를 상속받아 TestSpringRunner라는 클래스를 만들어준다. 그리고 bindJndi()라는 메서드를 생성해서 jndiTemplate이라는 객체를 만들어서 데이터 소스를 바인딩한다. 그러면 나중에 테스트 환경에서 jndi를 로드하려고 할 때, jndiTemplate에 바인딩되어 있는 java:comp/env/jdbc/ssafy라는 이름의 데이터 소스가 있기 때문에 WAS가 없어도 스프링 컨테이너에 빈을 등록해서 사용할 수 있게 된다. (참고로 테스트 환경을 아래 사진처럼 위에 만든 TestSpringRunner 클래스로 돌려줘야한다.
   그림 4) TestSpringRunner 환경에서 테스트해야한다.
  그림 4) TestSpringRunner 환경에서 테스트해야한다.
이렇게 하고나니 드디어 정상적으로 테스트를 통과하는 걸 확인할 수 있었다!!!!!!
   그림 5) 테스트를 통과하는 모습
  그림 5) 테스트를 통과하는 모습
JUnit은 항상 스프링 부트 환경에서 간단한 테스트만 해봐서 WAS 없이 스프링 환경에서 단위 테스트를 돌리려고 하니까 제대로 되지 않는 부분이 이렇게 많을 줄은 몰랐다. 제대로 된 단위 테스트를 만들기 위해서 테스트에 대한 공부가 많이 필요하다는 것을 이번 싸피 과제를 통해 알게 되었다.