私はSpringにかなり新しいので、モックされたデータソースを使用するJUnitテストを作成する方法と、それでJNDIコンテキストを使用する方法を疑問に思っていますか?現在、私のアプリケーションは、TomcatからJNDIコンテキストを使用して接続を取得し、その接続を介してデータベースからデータを取得します。だから、JNDI呼び出しとデータ取得をモックする必要があると思います。これに取り組むための最善の方法が素晴らしいと思うものについての良いポインタ!どうもありがとう!
通常、JNDI依存関係は、datasource-context.xml
:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<jee:jndi-lookup id="dataSource"
jndi-name="Java:comp/env/dataSource"
expected-type="javax.sql.DataSource" />
</beans>
テストリソースで別のファイルを作成し、テストデータソースを定義できますが、datasource-testcontext.xml
:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="org.hsqldb.jdbcDriver"
p:url="jdbc:hsqldb:hsql://localhost:9001"
p:username="sa"
p:password="" />
</beans>
そして、私のテストクラスでは本番環境の代わりにデータソースのテスト構成を使用 JNDIに依存します。
@ContextConfiguration({
"classpath*:META-INF/spring/datasource-testcontext.xml",
"classpath*:META-INF/spring/session-factory-context.xml"
})
public class MyTest {
}
データソースが別のファイルで定義されていない場合、JNDI呼び出しによって返されたオブジェクトを簡単にスタブ化できます。
org.springframework.mock.jndi
、つまり。 SimpleNamingContextBuilder
(このcalassのjavadocに例があります)。SimpleNamingContextBuilderを使用して、テストでjndiデータソースを使用可能にすることができます。
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("Java:comp/env/jdbc/mydatasource", dataSource);
builder.activate();
これはデータソースを正確にモッキングするわけではありませんが、テストのためにjndiを介してデータソースを利用可能にします。
SpringのAbstractDataSourceを拡張することにより、独自の模擬DataSourceを作成できます。
import Java.sql.Connection;
import Java.sql.SQLException;
import org.springframework.jdbc.datasource.AbstractDataSource;
/**
* Mock implementation of DataSource suitable for use in testing.
*
*
*/
public class MockDataSource extends AbstractDataSource {
private Connection connection;
/**
* Sets the connection returned by javax.sql.DataSource#getConnection()
* and javax.sql.DataSource#getConnection(Java.lang.String, Java.lang.String)
*
* @param connection
*/
public void setConnection(Connection connection) {
this.connection = connection;
}
/*
* (non-Javadoc)
* @see javax.sql.DataSource#getConnection()
*/
public Connection getConnection()
throws SQLException {
return connection;
}
/*
* (non-Javadoc)
* @see javax.sql.DataSource#getConnection(Java.lang.String, Java.lang.String)
*/
public Connection getConnection(String username, String password)
throws SQLException {
return connection;
}
}
接続のJNDIルックアップを残りのコードから分離します。データアクセスオブジェクト(DAO)にデータソースを挿入し、DAOのテストにMockDataSourceを使用します。
最初にbeans.xmlを参照し、次にデータソース構成をオーバーライドする、beans.test.xml構成を常に作成できます。
src/main/resources/beans.xml
<!-- Database configuration -->
<import resource="beans.datasource.jndi.xml" />
src/test/resources/beans.test.xml
<import resource="beans.xml" />
<import resource="beans.datasource.test.xml" />
JUnitテストクラス:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/beans.test.xml" })
public class ASRTests
{
...
}
Jndi Beanで、参照を宣言します
<jee:jndi-lookup expected-type="javax.sql.DataSource" id="mysqlDataSource" jndi-name="jdbc/mysql"/>
テストBeanで、データソースを宣言します
<bean id="mysqlDataSource" ...>
...
</bean>
テストデータソースBeanをテストフォルダーに移動することに注意してください。
春のorg.springframework.jndi.JndiObjectFactoryBean
はJNDIルックアップに最適です。そのドキュメントによると、スプリングベースのテストケースにもデフォルト値を挿入できます。
以下のスプリング設定を参照してください(spring-test-db-config.xmlという名前)
<bean id="dataSource" class="Oracle.jdbc.pool.OracleDataSource">
<property name="URL" value="jdbc:Oracle:thin:@localhost:1521:XE"/>
<property name="user" value="UNITTEST"/>
<property name="password" value="UNITTEST"/>
</bean>
<bean id="dataSourceFromJndi" class="org.springframework.jndi.JndiObjectFactoryBean">
<!-- Any junk value will suffice as that is always gonna throw NamingException -->
<property name="jndiName" value="jdbc/Ds"/>
<property name="defaultObject" ref="dataSource"/>
</bean>
他の構成ファイルで定義された追加Beanは、dataSourceFromJndi
Beanを参照するものとします
<!-- START OF SERVICES -->
<bean class="com.sample.Service" >
<property name="dataSource" ref="dataSourceFromJndi" />
</bean>
このアプローチの利点は、2つの異なるDB構成ファイルを保持できることです(1つは実稼働用、もう1つは単体テスト用です)。正しいものをインポートするだけです。テスト構成にはデフォルトのオブジェクトが含まれます。
Java Config .....
Junitテストケース
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DatabaseConfigStub.class}, loader= AnnotationConfigContextLoader.class)
public class DatabaseConfigTest {
@Autowired
private DataSource datasource;
@Autowired
private JdbcTemplate jdbcTemplate;
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testDataSource() {
assertNotNull(datasource);
assertNotNull(jdbcTemplate);
}
}
DatabaseConfigStub
public class DatabaseConfigStub {
private static final Logger log = Logger.getLogger(DatabaseConfigStub.class);
private static final String DS_NAME = "jdbc/DS_NAME";
@Bean
DataSource dataSource() {
JndiObjectFactoryBean jndiObjectBean = EasyMock.createMock(JndiObjectFactoryBean.class);
jndiObjectBean.setJndiName(DS_NAME);
jndiObjectBean.setResourceRef(true);
jndiObjectBean.setProxyInterfaces(DataSource.class);
EasyMock.expect( (DataSource)jndiObjectBean.getObject()).andReturn(new DataSource() {
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
public Connection getConnection(String username, String password)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
public Connection getConnection() throws SQLException {
// TODO Auto-generated method stub
return null;
}
}
);
EasyMock.replay(jndiObjectBean);
return (DataSource) jndiObjectBean.getObject();
}
@Bean
JdbcTemplate jdbcTemplate(){
return new JdbcTemplate( dataSource());
}
}
Simple-JNDIを使用することもできます。これは、J2EEコンテナの外部でJNDIコンテキストを操作するためのメモリ内JNDI実装です。本番およびテストで同じBean定義ファイルを使用できます。これが実稼働環境でのBean定義であると想定します。
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="Java:comp/env/jdbc/DataSource"/>
</bean>
<bean id="dao" class="my.Dao">
<property name="dataSource" ref="dataSource" />
</bean>
このようなプロパティファイルを作成します
type=javax.sql.DataSource
driverClassName=org.gjt.mm.mysql.Driver
url=jdbc:mysql://localhost/testdb
username=user_name
password=password
クラスパスに、Simple-JNDIとjndi.propertiesファイルを少し設定して配置します。その後、通常どおりデータソースにアクセスします。