Spring+JUnit+DbUnitではまる。。。

久しぶりにDbUnitを使おうとおもったらはまりまくった。

環境はeclipse3.4.1上のプロジェクト(古いけどこのときのシステムはこれで統一してたので。。。)
Springは2.5.6

まずアノテーション@RunWith(SpringJUnit4ClassRunner.class)を追加すると、

型 org.junit.internal.runners.JUnit4ClassRunner を解決できません。 必要な .class ファイルから間接的に参照されています

のエラーメッセージ。。。

Springにはいっていたjunit-4.4.jarをクラスパスに追加して解決。

初期データをDataSetからCLEAN_INSERTを行っても、テスト実行時は別のトランザクションになってしまいテストができなかった。。。

データソースをとってくるところをorg.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
に変更。
元のDBCPのところはidをdbcpDataSourceにして以下を追加

  <bean id="dataSource"
    class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <constructor-arg ref="dbcpDataSource" />
  </bean>

これで解決。

  • 3つ目のはまり実行時例外

さてテストを実行しようとしたら

java.lang.SecurityException: class "org.junit.internal.runners.JUnit4ClassRunner"'s signer information does not match signer information of other classes in the same package

はぅ。。。
ライブラリが競合してたみたい。。。
junit-4.4.jarの順序を変更したら動くようになった。



さて、テストがんばりましょか。

とりあえず、動いたソースをアップ
内容は初期データを取り込んだテーブルをSELECTで取り出し
結果をExcelで比較する。
BeanのリストをIDataSetにするのは、
http://sourceforge.jp/projects/dbunitng/
を使わせていただきました。

import java.io.BufferedInputStream;
import java.net.URL;
import java.util.List;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.log4j.xml.DOMConfigurator;
import org.dbunit.Assertion;
import org.dbunit.DataSourceDatabaseTester;
import org.dbunit.IDatabaseTester;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.excel.XlsDataSet;
import org.dbunitng.dataset.BeanListConverter;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@TransactionConfiguration(defaultRollback = true)
@ContextConfiguration(locations = "/resources/spring/batchApplicationContext.xml")
public class DbUnitTest {
    private static final String LOG4J_CONFIG_FILE = "src/main/resources/log4j/log4j.xml";
    private IDatabaseTester tester;

    @Autowired
    private DbUnitDao dbUnitDao;
    @Resource
    private DataSource dataSource;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        DOMConfigurator.configure(LOG4J_CONFIG_FILE);
    }

    @Before
    public void setUp() throws Exception {
        tester = new DataSourceDatabaseTester(dataSource);
        tester.setDataSet(getDataSet());
        tester.onSetup();
    }

    @After
    public void after() throws Exception {
        tester.onTearDown();
    }

    protected IDataSet getDataSet() throws Exception {
        URL url = DbUnitTest.class.getResource("import-data.xls");
        BufferedInputStream is = new BufferedInputStream(url.openStream());
        XlsDataSet dataset = new XlsDataSet(is);

        return dataset;
    }

    @Test
    public void hogehoge() throws Exception {
        List<DbUnitBean> list = dbUnitDao.queryAll();
        BeanListConverter converter = new BeanListConverter(list);
        IDataSet dataSet = converter.convert();

        URL url = DbUnitTest.class.getResource("expected-data.xls");
        BufferedInputStream is = new BufferedInputStream(url.openStream());
        XlsDataSet expected = new XlsDataSet(is);

        Assertion.assertEquals(expected, dataSet);

    }
}

STS2.3.3M2 リポジトリが足りない。

Pluginのリポジトリに以下を追加しないとaspectjtoolsが入らない

	<pluginRepositories>
		<pluginRepository>
			<id>spring-maven-release</id>
			<name>Spring Maven Release Repository</name>
			<url>http://maven.springframework.org/release</url>
		</pluginRepository>
		<pluginRepository>
			<id>spring-maven-milestone</id>
			<name>Spring Maven Milestone Repository</name>
			<url>http://maven.springframework.org/milestone</url>
		</pluginRepository>
		<pluginRepository>
			<id>spring-roo-repository</id>
			<name>Spring Roo Repository</name>
			<url>http://spring-roo-repository.springsource.org/release</url>
		</pluginRepository>
	</pluginRepositories>

ここを追加しないとhibernate-jpa-2.0-apiなどhibernateまわりのjarファイルがダウンロードされない。

        <repository>
            <id>JBOSS</id>
            <name>JBoss Repository</name>
            <url>http://repository.jboss.org/maven2/</url>
        </repository>

今のところ気付いたのはこれだけ。

Firefoxで常にスクロールバー表示

センタリングされた画面で、表示が画面に収まる場合はFirefoxでスクロールバーがない状態になってしまう。

スクロールバーがある場合とない場合でセンター位置がことなるため、遷移するとびみょーにずれたように感じてしまう。そこで常にスクロールバーを表示させればこのようなことが防げるようになります。
IEは常に表示されるのでこのようなことはないのですが・・・

常に表示させるためのスタイルシートがこれになります。

html {
  overflow-y: scroll;
}

Firefox以外のブラウザやバージョンによってはうまくいかない場合があるので、ご注意を。。。

DataAccessExceptionのマッピング変更

Springを利用したDBへのアクセスでSQLExceptionはDataAccessExceptionの継承クラスに変換されます。

この変換には「sql-error-codes.xml」で定義された情報で、変換されるクラスが決定される。
このXMLファイルは、springのjarファイル内の「org.springframework.jdbc.suport」に存在しており、自分用にカスタマイズしたい場合は、このファイルを編集して、クラスパスの通っているディレクトリの直下に配置することでオーバーライドすることが可能となっている。

さらに自分で作成したDataAccessExceptionの継承クラスに変換したい場合は、以下のように定義します。
ここで定義できるのは、DataAccessExceptionの継承クラスしか定義できません。
#PostgreSQLをサンプルに

<bean id="PostgreSQL" class="org.springframework.jdbc.support.SQLErrorCodes">
<property name="useSqlStateForTranslation">
<value>true</value>
</property>
<property name="badSqlGrammarCodes">
<value>03000,42000,42601,42602,42622,42804,42P01</value>
</property>
<property name="dataAccessResourceFailureCodes">
<value>53000,53100,53200,53300</value>
</property>
<property name="dataIntegrityViolationCodes">
<value>23000,23502,23514</value>
</property>
<property name="cannotAcquireLockCodes">
<value>55P03</value>
</property>
<property name="cannotSerializeTransactionCodes">
<value>40001</value>
</property>
<property name="deadlockLoserCodes">
<value>40P01</value>
</property>
<property name="customTranslations">
<list>
<!-- ここから -- >
<bean class="org.springframework.jdbc.support.CustomSQLErrorCodesTranslation">
<!-- 対応するSQL例外のエラーコード -->
<property name="errorCodes" value="23503" />
<!-- 変換する例外クラス -->
<property name="exceptionClass" value="jdbc.ForeignKeyException" />
</bean>
<bean class="org.springframework.jdbc.support.CustomSQLErrorCodesTranslation">
<property name="errorCodes" value="23505" />
<property name="exceptionClass" value="jdbc.DuplicateKeyException" />
</bean>
<!-- ここまで -->
</list>
</property>
</bean>

※Springframework2.5.4で確認しました。

XPのディスクにアクセスできない

友達からの頼まれごとでVistaにXPがインストールされているHDDの情報を抜き出す作業をしました。

XPが入っているほうはHDDしかなかったので、HDDケースに入れてUSBでVistaマシンにつないで中身が見れるの確認できたのですが、ユーザのホームディレクトリを見ようとするとアクセス権がないと言われてアクセスできない。。。

お気に入りやマイドキュメントの中身を移行したいのに・・・

少し調べてみるとVistaには「パスワード保護共有」というのがあり、このせいでアクセスできない様子。

「コントロールパネル」−「ネットワークと共有センター」を開き、「パスワード保護共有」の設定を無効に設定。

これでアクセスできるようになりました。(少し焦ったけど・・・)

SSLアクセラレータ利用時のリダイレクト

HttpServletResponse#sendRedirect(java.lang.String location)を使ってリダイレクトを行った場合に、引数に渡される「location」が相対URLの場合は絶対URLが構築されます。

例)
 「http://host.domain/context/hoge.jsp」 にアクセスした際に、この処理の中で
 「/foo.jsp」を引数に渡してリダイレクトを行うと、クライアントには
 「http://host.domain/context/foo.jsp」として渡されます。

通常はこれで問題ないのですが、SSLアクセラレータを利用した場合は、
クライアントのアクセスしたURL:「https://host.domain/context/hoge.jsp
tomcatが受け付けたURL:「http://host.domain/context/hoge.jsp
となり「https」が「http」となってしまいます。
このためリダイレクトの絶対URLが構築された際に「http」として構築されてしまいます。

この問題を回避するにはserver.xmlのconnectorタグの属性を変更すれば回避できます。
proxyName="サーバ名"
proxyPort="ポート番号" ※通常SSLなら443
scheme="スキーマ" ※通常SSLならhttps
secure="true" これは設定しなくてもよいけど、request.isSecure()の戻り値がtrueになる。

参考
http://tomcat.apache.org/tomcat-6.0-doc/config/ajp.html