DE EN

Wie man für JUnit JNDI Resourcen mit Spring erstellt

von

Bis vor kurzem hatte ich in meinen JUnit Tests statische Methoden um eine “In-Memory”-Datenbank (HSQLDB) zu erstellen. “In-Memory” bedeutet, die Datenbank lebt ausschließlich im Arbeitsspeicher. Diese Methoden habe ich in den JUnit-Methoden setUp und tearDown aufgerufen. Das fühlte sich immer etwas unnatürlich für mich an, weil ich doch Spring verwendete und eigentlich alles durch die Spring Application Context laufen sollte.

Erstellen einer einfachen JNDI Bean

Bei mir lief JNDI in Produktion, also hatte ich eine JNDI Resource für meine Anwendung zu erstellen. Auch im JUnit Context. Eine einfache Spring-Bean erstellt mit Apache Commons DBCP erledigt den Job ziemlich gut:

public class JndiBean {

    public JndiBean() {
        try {
            DriverAdapterCPDS cpds = new DriverAdapterCPDS();
            cpds.setDriver("org.hsqldb.jdbc.JDBCDriver");
            cpds.setUrl("jdbc:hsqldb:mem:testdb");
            cpds.setUser("SA");
            cpds.setPassword("");

            SharedPoolDataSource dataSource = new SharedPoolDataSource();
            dataSource.setConnectionPoolDataSource(cpds);
            dataSource.setMaxActive(10);
            dataSource.setMaxWait(50);

            SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
            builder.bind("java:comp/env/jdbc/timeandbill", dataSource);
            builder.activate();
        } catch (NamingException | ClassNotFoundException ex) {
            ex.printStackTrace();
        }
    }
}

Die Einstellung sollte natürlich nicht einfach so in ernsthaftere Szenarien übernommen werden ohne genau darüber nachzudenken. Aber für JUnit reicht es recht gut.

Zunächst erstellte ich einen Driver Adapter. Er enthält alles, was ich für meine Verbindung zur Datenbank benötige. Es könnte jetzt MySQL sein, oder PostgreSQL oder was auch immer.

Dann erstellte ich einen SharedPoolDatasource. Pooling zählt in diesem Szenario natürlich nichts, weil wir die Tests oft sequenziell laufen lassen und ohnehin nicht gerade viele Verbindungen benötigen. Allerdings wollte ich hier so nah wie möglich an meinem Produktionssystem bleiben, daher spendierte ich hier einen Connection-Pool.

Der SimpleNamingContextBuilder bindet dann letztlich den zuvor erstellten DataSource an den JNDI Kontext. Das ist ziemlich einfach. Erstellen, binden, aktivieren. Das war’s.

Eine JNDI Bean zum Kontext hinzufügen

Der nächste Schritt ist es, eine zweite applicationContext.xml anzulegen, die dann nur von JUnit Tests geladen wird. Die Datei befindet sich in meinem Unit-Test Ordner und enthält:

<bean id="jndi" class="de.grobmeier.tab.webapp.JndiBean" lazy-init="false" />

Die folgende Annotations in meinen Tests stellen dann sicher, dass mein Applications-Kontext geladen wird.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath*:applicationContext.xml"})
public class TimeConverterTest {

In Produktion sieht mein applicationContext eher so aus:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName" value="java:comp/env/jdbc/timeandbill"/>
	<property name="resourceRef" value="true" />
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
</bean>

In meinen JUnit Tests läuft natürlich kein Java EE Server. Stattdessen wird die JNDI Verbindung manuell erstellt. In Produktion dagegen wird der Test-Kontext nicht geladen und der Java EE Container stellt die Resource von selbst bereit.

Tags: #java #spring #junit #jndi #java ee

Newsletter

ABMELDEN