19

問題文

データベースに接続するメソッドで junit テストを実行できるようにしたいと考えています。

現在のセットアップ

Eclipse Java EE IDE – Java コードはフレームワークを使用していません。開発者 (私を含む) は、コードを Spring フレームワークに移行しようとする前に、現在のレガシー コードのより堅牢なテストを行い、その動作がまだ正しいことを途中で証明できるようにしたいと考えています。

JBoss 4.2 – ベンダー ソフトウェア ( Adobe LiveCycle ES2 ) によるバージョン制限。Java Web アプリケーションは、JBoss のこのセットアップを使用して実行し、Adobe LiveCycle API を利用します。

ベンダーが設定した JBoss を Eclipse 内で正常に実行することができませんでした。Adobe LiveCycle 用の JBoss の設定をサポートする会社に連絡するなど、これを試みるのに何週間も費やしました。おそらく、問題は Eclipse の設定でのメモリ制限の問題ですが、メモリ設定を変更しても、これまでのところ Eclipse 内で JBoss サーバーを正常に起動できませんでした。今のところ、JBoss を Eclipse 内で実行する試みは保留中です。

データベース接続は、JBoss が起動時にロードする JNDI データ ソースで定義されます。Web アプリケーションと Adob​​e LiveCycle の両方で、このデータ ソースへの接続を作成する必要があります。

コード

問題の核心に焦点を当てるために、このコード スニペットのエラー チェックとクラス構造について詳しく説明します。うまくいけば、それが他の人に問題を引き起こさないでしょう。角括弧内のテキストは実際のテキストではありません。

接続を作成するコードは次のようなものです。

Properties props = new Properties();
FileInputStream in = null;
in = new FileInputStream(System.getProperty("[Properties File Alias]"));
props.load(in);
String dsName = props.getProperty(“[JNDI data source name here]”); 
InitialContext jndiCntx = new InitialContext();
DataSource ds = (DataSource) jndiCntx.lookup(dsName);
Ds.getConnection();

このコードに変更を加えることなく、このコードに依存するメソッドをテストできるようにしたいと考えています。

properties-service.xml ファイル内のプロパティ ファイル エイリアスへの参照:

  <!-- ==================================================================== -->
  <!-- System Properties Service                                            -->
  <!-- ==================================================================== -->

  <!-- Allows rich access to system properties.-->

<mbean code="org.jboss.varia.property.SystemPropertiesService" 
 name="jboss:type=Service,name=SystemProperties">
  <attribute name="Properties">
    [Folder Alias]=[filepath1]
    [Properties File Alias]=[filepath2]
  </attribute>
</mbean>

filepath2 にあるプロパティ ファイルのスニペット

[JNDI data source name]=java:/[JNDI data source name]

このデータ ソースの JNDI xml ファイルは、次のように設定されます。

<datasources>
  <local-tx-datasource>
    <jndi-name>[JNDI data source name here]</jndi-name>
    <connection-url>jdbc:teradata://[url]/database=[database name]</connection-url>
    <driver-class>com.teradata.jdbc.TeraDriver</driver-class>
    <user-name>[user name]</user-name>
    <password>[password]</password>
    <!-- sql to call on an existing pooled connection when it is obtained from pool -->
    <check-valid-connection-sql>SELECT 1+1</check-valid-connection-sql>
  </local-tx-datasource>
</datasources>

解決策がどこにあるのかについての私の考え

上記のコードが探しているプロパティを JBoss なしで利用できるようにするために @BeforeClass メソッドでできることはありますか? java.util.Properties クラスの setProperty メソッドを何らかの形で使用しているのでしょうか。また、構成設定の重複を減らすために、可能であれば JBoss が読み取るのと同じ JNDI xml ファイルを使用したいと考えています。

これまでのところ、私の調査はすべて「Spring を使用する」というアドバイスで終わっていますが、まだワームの缶を開ける準備ができていないと思います。私は JBoss の専門家ではありませんが、有益な回答を得るために JBoss セットアップの詳細が必要な場合は、それらを入手するために最善を尽くします。

Stackoverflow 調査の参考文献:
spring を使用した junit での Jndi ルックアップ
コンテナー外の JNDI データ ソース
その他の調査の参考文献:
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Properties.html
http:/ /docs.oracle.com/javase/jndi/tutorial/basics/prepare/initial.html

4

4 に答える 4

8

あなたの問題に対する非常に簡単な答えがありますが、あなたはそれを気に入らないでしょう:しないでください.

定義上、ユニット テストは単一のユニットの機能を検証する必要があります (ユニットのサイズは異なる場合がありますが、自給自足である必要があります)。テストが Web サービスやデータベースなどに依存するセットアップを作成することは非生産的です。テストの速度が低下し、問題が発生する可能性のある無数の可能性が含まれます (ネットワーク接続の失敗、データ セットの変更など)。 ) テスト中、作業している実際のコードとは何の関係もありません。最も重要なことは、テストがはるかに困難で複雑になることです。

代わりに、テスト中にモック オブジェクトまたは同様のテスト ダブルを簡単に置き換えることができるように、レガシ コードをデータ ソースから分離する方法を探す必要があります。

スタック全体の整合性を検証するためにテストを作成する必要がありますが、それらは統合テストと呼ばれ、より高いレベルの抽象化で動作します。個人的には、ユニット自体が配置され、テストされ、機能するまで、これらの記述を延期することを好みます。少なくとも、サービス コールやプロトコルが日常的に変更されることを期待しなくなるまでは。

あなたの場合、最も明白な戦略は、Web サービスへのすべての呼び出しを 1 つ以上の個別のクラスにカプセル化し、ビジネス オブジェクトが依存できるインターフェイスを抽出し、ユニット テストに同じインターフェイスを実装するモックを使用することです。

たとえば、住所データベースを呼び出すビジネス オブジェクトがある場合は、JNDI 検索コードを という新しいサービス クラスにコピーする必要がありますAddressServiceImpl。そのパブリック メソッドは、JNDI データソースのすべてのメソッド シグネチャを模倣する必要があります。次に、それらをAddressServiceインターフェイスに抽出します。

次に、簡単な統合テストを作成して、新しいクラスが機能することを確認できます。すべてのメソッドを 1 回呼び出して、適切な結果が得られるかどうかを確認します。これの利点は、(元のデータベースではなく) テスト データベースを指す JNDI 構成を提供できることです。これには、テスト データセットを入力して、常に期待される結果が得られるようにすることができます。これには必ずしも JBoss インスタンスが必要というわけではありません (ただし、Eclipse 統合で問題が発生したことはありません)。データ ソース自体が同じように動作する限り、他の JNDI プロバイダーは機能するはずです。明確にするために、これを一度テストしたら、忘れてください。少なくとも実際のサービス方法が変わるまでは。

サービスが機能していることを確認したら、次のタスクはすべての依存クラスを調べて、データソースへの直接呼び出しを AddressService インターフェイスへの呼び出しに置き換えることです。そして、その時点から、他の場所でテストする必要があることを心配することなく、実際のビジネス メソッドに単体テストを実装するための適切なセットアップができます ;)

編集

私はMockitoの推奨事項に二番目です。とてもいいです!

于 2012-10-24T16:43:49.810 に答える
1

JBoss AS7 の一部のレガシー コードで非常によく似た状況がありました。その場合、リファクタリングは範囲外でした

JBoss はデータソースへのリモート アクセスをサポートしていないため、JBoss からデータソースを取得することをあきらめました。

ただし、理想的には、単体テストを実行するために実行中の JBoss インスタンスに依存させたくないし、JBoss 内で単体テストを実行する必要もありません。これは、自己完結型の単体テストの概念に反するものです (ただし、データベースを実行する必要があります:))。

幸いなことに、アプリが使用する初期コンテキストは、実行中の JBoss インスタンスから取得する必要はありません別の質問への回答で参照されているこの記事を見た後、独自の初期コンテキストを作成し、独自のデータソース オブジェクトを設定することができました。

テスト対象のクラスは通常、コンテナー内で実行され、コンテナーが提供するコンテキストを取得するために次のようなことを行うだけなので、これはコードに依存関係を作成しなくても機能します。

InitialContext ic = new InitialContext();
DataSource ds = (DataSource)ic.lookup(DATA_SOURCE_NAME);

コンテナーによって既に設定されているため、コンストラクターに環境を指定する必要はありません。

単体テストがコンテナーの代わりになり、コンテキストを提供するために、それを作成し、名前をバインドします。

InitialContext ic = new InitialContext();

// Construct DataSource
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
ds.setURL("url");
ds.setUser("username");
ds.setPassword("password");

ic.bind(DATA_SOURCE_NAME, ds);

これは、各テスト クラスの@BeforeClassメソッドで発生する必要があります。

これで、テスト対象のクラスは、単体テストでの実行時初期コンテキストを取得し、デプロイ時にコンテナーのコンテキストを取得します。

于 2014-02-04T17:38:08.627 に答える
0

InitialContextへの呼び出しから必要なものをすべて返す偽の実装でテストを実行できますlookup(String)

このような偽の実装を可能にするモック/偽装ツールはJMockitです。偽の実装は次のように記述されます。

public class FakeInitialContext extends MockUp<InitialContext>
{
    @Mock
    public Object lookup(String name)
    {
        // Return whatever is needed based on "name".
    }
}

これを JUnit/TestNG テスト実行に適用するには、jmockit.jar をランタイム クラスパス (この場合は junit.jar の前) に追加し、「jmockit-mocks」システム プロパティを偽のクラスの名前に設定します-Djmockit-mocks=com.whatever.FakeInitialContext

もちろん、「Expectations & Verifications」モック API を使用して、依存関係を簡単にモックできる真の JUnit/TestNG 単体テストを作成することもできます。

(PS: 完全な開示のために、私は JMockit プロジェクトの作成者です。)

于 2012-10-24T17:19:54.677 に答える
0

Git や Maven などのツールを使用している場合、これは簡単に実行できます。開発と QA に沿って、UnitTest 固有のプロパティ ファイルをチェックインします。Maven とそのprofile機能を使用して、UnitTest ファイルを必要な場所にコピーするプロファイルを指定します。これは、異なるプロファイルをアクティブにして実行した場合の dev および qa と同じです。

これには魔法はありません。春は何よりも複雑さをもたらします。このような単純さを導入することは絶対にありません。

于 2012-10-24T16:58:59.903 に答える