본문 바로가기
Spring/Spring

[Spring] JUnit Test에 JNDI 적용

by J4J 2021. 4. 5.
300x250
반응형

안녕하세요. J4J입니다.

 

이번 포스팅은 JUnit Test에 JNDI 적용하는 방법에 대해 적어보는 시간을 가져보려고 합니다.

 

 

 

이전 포스팅을 보시면 JNDI를 이용하여 데이터베이스를 연결하는 방법에 대해 설명드렸었습니다.

 

하지만 JNDI를 사용하게 되면 단위 테스트를 진행할 때는 서버를 실행시키지 않으니 데이터베이스의 정보를 알 수 없는 문제가 발생하게 됩니다.

 

역시나 JNDI와 단위 테스트를 동시에 사용할 수 있는 방법이 있었고 어떻게 설정하는지 보여드리도록 하겠습니다.

 

 

프로젝트 설정

 

제가 설정했었던 RootContext파일은 다음과 같습니다.

 

package com.spring.jndi.config;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@ComponentScan(basePackages = {"com.spring.jndi.service"})
@MapperScan(basePackages = {"com.spring.jndi.repository"})
@EnableJpaRepositories(basePackages = {"com.spring.jndi.repository"})
public class RootContext {	
//	기존 방식
//	@Bean
//	public BasicDataSource dataSource() {
//		BasicDataSource datasource = new BasicDataSource();
//		datasource.setDriverClassName("com.mysql.cj.jdbc.Driver");
//		datasource.setUrl("jdbc:mysql://localhost:3306/jndi?serverTimezone=UTC");
//		datasource.setUsername("root");
//		datasource.setPassword("root");
//		
//		return datasource;
//	}
	
	// jndi 방식
	@Bean
	public DataSource dataSource() {
		JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
		return dataSourceLookup.getDataSource("jndi/mysql");
	}
	
	// jpa 설정
	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
		LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
		entityManagerFactory.setDataSource(dataSource());
		entityManagerFactory.setPersistenceUnitName("jpa-mysql");
		entityManagerFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
		
		return entityManagerFactory;
	}
	
	// mybatis 설정
	@Bean
	public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
		SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
		sqlSessionFactory.setDataSource(dataSource());
		sqlSessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis-config.xml"));
		
		return sqlSessionFactory;
	}
   
	@Bean
	public SqlSessionTemplate sqlSession(SqlSessionFactoryBean sqlsessionFactory) throws Exception {
		return new SqlSessionTemplate(sqlsessionFactory.getObject());
	}
	
	// transactional 설정
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception {
		DataSourceTransactionManager myBatisTransactionManager = new DataSourceTransactionManager();
		myBatisTransactionManager.setDataSource(dataSource());
		
		JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
		jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
		
		ChainedTransactionManager transactionManager = new ChainedTransactionManager(jpaTransactionManager, myBatisTransactionManager);
		return transactionManager;
	}
}

 

 

반응형

 

 

해당 파일을 기반으로 단위 테스트에서 JNDI사용을 위해 다음과 같이 설정해주면 됩니다.

 

1. SelfSpringRunner 클래스 생성 (src/test/java의 com.spring.jndi.config.SelfSpringRunner)

 

package com.spring.jndi.config;

import org.apache.commons.dbcp2.BasicDataSource;
import org.junit.runners.model.InitializationError;
import org.springframework.jndi.JndiTemplate;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public final class SelfSpringRunner extends SpringJUnit4ClassRunner {

	public SelfSpringRunner(Class<?> clazz) throws InitializationError {
		super(clazz);
		try {
			bindJNDI();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	private void bindJNDI() throws Exception {
        	SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
        	builder.activate();
		
		JndiTemplate jndiTempalte = new JndiTemplate();
        
		BasicDataSource datasource = new BasicDataSource();
		datasource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		datasource.setUrl("jdbc:mysql://localhost:3306/jndi?serverTimezone=UTC");
		datasource.setUsername("root");
		datasource.setPassword("root");
        
        	jndiTempalte.bind("jndi/mysql", datasource);
	}
}

 

 

해당 코드를 작성하면 SimpleNamingContextBuilder에 취소선이 그어질 것입니다.

 

하지만 취소선이 그어진다고 코드를 작성하지 않으면 정상적으로 동작되지 않습니다.

 

그리고 대체되는 클래스가 있나 찾아봤는데 따로 발견하지 못했습니다.

 

혹시 대체되는 클래스를 알고 계시는 분은 댓글 부탁드립니다 ㅠㅠ.

 

 

2. 단위 테스트

 

package com.spring.jndi;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;

import com.spring.jndi.config.RootContext;
import com.spring.jndi.config.SelfSpringRunner;
import com.spring.jndi.repository.ExamJpaRepository;

import lombok.extern.slf4j.Slf4j;

@RunWith(SelfSpringRunner.class) // SpringRunner대신 JNDI정보를 담은 SelfSpringRunner로 등록
@ContextConfiguration(classes = RootContext.class)
@Slf4j
public class JNDITest {
	
	@Autowired
	ExamJpaRepository examJpaRepository;

	@Test
	public void test() {
		log.info(examJpaRepository.findAll().toString());
	}
}

 

 

위와 같이 설정하고 단위 테스트를 진행하면 WAS 서버에 JNDI를 등록해둔 것처럼 정상적으로 인식하여 다음과 같이 동작됩니다.

 

...

INFO : org.springframework.mock.jndi.SimpleNamingContextBuilder - Activating simple JNDI environment
INFO : org.springframework.mock.jndi.SimpleNamingContext - Static JNDI binding: [jndi/mysql] = [org.apache.commons.dbcp2.BasicDataSource@42d8062c]

...

Hibernate: 
    /* select
        generatedAlias0 
    from
        ExamEntity as generatedAlias0 */ select
            examentity0_.id as id1_0_,
            examentity0_.name as name2_0_,
            examentity0_.price as price3_0_ 
        from
            exam examentity0_
INFO : com.spring.jndi.JNDITest - [ExamEntity(id=1, name=정보처리기사, price=30000), ExamEntity(id=2, name=정보처리산업기사, price=20000), ExamEntity(id=3, name=SQLD, price=25000)]

 

 

참조

 

[Spring Fw] 스프링프레임워크에서 JUnit 을 이용한 API 테스트 : Spring Framework + JUnit + JNDI

 

 

 

 

이상으로 JUnit Test에 JNDI 적용하는 방법에 대해 간단하게 알아보는 시간이었습니다.

 

읽어주셔서 감사합니다.

728x90
반응형

댓글