JUnit:統合テストとユニットテストの分割


126

私はJunitテストの負荷を継承しましたが、これらのテスト(ほとんどが機能していないことを除いて)は、実際の単体テストと統合テスト(外部システム、dbなどが必要)の混合です。

だから私はそれらを実際に分離する方法を考えているので、ユニットテストを素晴らしく迅速に実行でき、その後統合テストを実行できます。

オプションは...

  1. それらを別々のディレクトリに分割します。

  2. (v3から)Junit4に移動し、クラスに注釈を付けてそれらを分離します。

  3. ファイルの命名規則を使用して、クラス(AdapterATestとAdapterAIntergrationTest)を識別します。

3には、Eclipseに「選択したプロジェクト/パッケージまたはフォルダーですべてのテストを実行する」オプションがあるという問題があります。したがって、統合テストを実行するだけでは非常に困難になります。

2:開発者がユニットテストクラスで統合テストを作成し始める可能性があり、混乱するだけです。

1:最も近い解決策のように見えますが、私の直感はそこにもっと良い解決策があるはずだと言っています。

それが私の質問です。統合テストと適切な単体テストをどのように分解するのでしょうか。


ご入力いただきありがとうございます。これは主観的な質問であり、正解ではありません。しかし、あなたは私がリストしたもの以外に他に選択肢がないことを理解するのを助けてくれました。現時点ではディレクトリ構造を使用してJUnit4に移動するつもりですが、まだ分割するためにアノテーションを使用していません。
jeff porter 2010

回答:


10

私は現在、組織のポリシー(およびJunit 3のレガシー)のために別のディレクトリを使用していますが、私は注釈に移行したいと思っています。今はJUnit 4にいます。

ユニットテストクラスに統合テストを置く開発者については、あまり心配しません。必要に応じて、コーディング標準にルールを追加してください。

アノテーションや物理的にクラスを分離する以外に、他にどのような解決策があるのか​​知りたいです。


145

JUnitカテゴリとMavenを使用すると、非常に簡単に分割できます。

これは、ユニットおよび統合テストを分割することによって、非常に簡単に以下に示されています。

マーカーインターフェイスを定義する

カテゴリを使用してテストをグループ化する最初のステップは、マーカーインターフェイスを作成することです。

このインターフェイスは、統合テストとして実行するすべてのテストをマークするために使用されます。

public interface IntegrationTest {}

テストクラスをマークする

カテゴリアノテーションをテストクラスの上部に追加します。新しいインターフェースの名前をとります。

import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class ExampleIntegrationTest{
  @Test
  public void longRunningServiceTest() throws Exception {
  }
}

Mavenユニットテストの構成

このソリューションの優れている点は、単体テストの面では何も変更されないことです。

maven surefireプラグインに構成を追加して、統合テストを無視するようにします。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <includes>
      <include>**/*.class</include>
    </includes>
    <excludedGroups>com.test.annotation.type.IntegrationTest</excludedGroups>
  </configuration>
</plugin>

mvn clean testを実行すると、マークされていない単体テストのみが実行されます。

Maven統合テストの構成

この場合も、設定は非常に簡単です。

統合テストのみを実行するには、これを使用します:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <groups>com.test.annotation.type.IntegrationTest</groups>
  </configuration>
</plugin>

これをidを持つプロファイルでラップするとIT、を使用して実行できるのは高速テストのみになりますmvn clean install。統合/スローテストのみを実行するには、を使用しますmvn clean install -P IT

ただし、ほとんどの場合、デフォルトで高速テストを実行し、すべてのテストをで実行する必要があります-P IT。その場合は、トリックを使用する必要があります。

<profiles>
    <profile>
        <id>IT</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>java.io.Serializable</excludedGroups> <!-- An empty element doesn't overwrite, so I'm using an interface here which no one will ever use -->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

ご覧のとおり、で注釈が付けられたテストを除外していjava.io.Serializableます。これは、プロファイルがSurefireプラグインのデフォルト設定を継承するために必要です。つまり、<excludedGroups/>またはと言っても<excludedGroups></excludedGroups>、値com.test.annotation.type.IntegrationTestが使用されます。

またnone、クラスパスのインターフェースでなければならないため、使用できません(Mavenがこれをチェックします)。

ノート:

  • への依存関係surefire-junit47は、Mavenが自動的にJUnit 4ランナーに切り替えない場合にのみ必要です。groupsor excludedGroups要素を使用すると、切り替えがトリガーされます。こちらをご覧ください
  • 上記のコードのほとんどは、Maven Failsafeプラグインのドキュメントから取得されました。このページの「JUnitカテゴリの使用」のセクションを参照してください
  • テスト中に、@RunWith()注釈を使用してスイートまたはSpringベースのテストを実行した場合でも、これが機能することがわかりました。

18
最後のpom.xmlフラグメントにエラーがあると思います。「テスト」フェーズと同じスニペットを貼り付けました。統合テストはまだ除外されており、Mavenフェーズにバインドされていません。
アレックス

1
実際、最後のpomフラグメントは、コピーと貼り付けの間違いです。maven-failsafe-pluginが表示されます。
Paulo Merson 2013

2
では、2番目のxmlは何でしょうか。:O
Liv 2013年

デフォルトのMavenプロファイルを使用する場合、トリック(Serializableの最後の魔法)を使用する必要はありません
user831217

これは実際には受け入れられる答えであるはずです。なぜなら、これは実際には、さまざまなテストをどこに置くかについての哲学的な議論ではなく、質問に対する解決策だからです。
Bwvolleyball 2017年

40

単体テストの実行にはMaven Surefireプラグインを使用し、統合テストの実行にはMaven Failsafeプラグインを使用します。単体テストは、**/Test*.java **/*Test.java **/*TestCase.java命名規則、統合テスト-に従います**/IT*.java **/*IT.java **/*ITCase.java。したがって、実際にはオプション3です。

いくつかのプロジェクトでは、TestNGを使用して、統合/単体テスト用にさまざまなテストグループを定義していますが、これはおそらくあなたには適していません。


1
maven + surefire + failsafe + junitコンボの+1。フェイルセーフが「IT *」を自動的に実行することを認識していませんでした。甘い。
PapaFreud 2011年

13

私はそれを持っているだけでJunit4に移動します:)

それらを異なるテストスイートに分離できます。Junit3でどのように構成されているかはわかりませんが、Junit4では、テストスイートを構築して実際のユニットテストをすべて1つにまとめ、2番目のスイートを統合テストに使用するだけで簡単です。

Eclipseで両方のスイートの実行構成を定義すると、単一のスイートを簡単に実行できます。これらのスイートは、自動化されたプロセスから起動することもできます。これにより、ソースが変更されるたびに単体テストを実行できます。統合テスト(本当に大きい場合)を1日に1回または1時間に1回だけ実行できます。


9

IfProfileValueスプリングアノテーションを使用すると、Mavenプラグインや構成を必要とせずにこれを実現できます。

IfProfileValueを使用して統合テストクラスまたはメソッドに注釈を付ける

import org.springframework.test.annotation.IfProfileValue;

@IfProfileValue(name="test-groups", value="integration")
public class ExampleIntegrationTest{
    @Test
    public void longRunningServiceTest() throws Exception {
    }
} 

単体テストのみを使用して実行するには:

mvn clean test

統合テストと単体テストを使用して実行するには:

mvn clean test -Dtest-groups=integration

また、IDEで「すべてのテストを実行」はユニットテストのみを実行します。-Dtest-groups=integration統合テストと単体テストの両方を実行するには、VM引数に追加します。


このアプローチは素晴らしくシンプルですが、問題はデフォルトですべてのテスト(統合テストを含む)を実行したいということです。それはこのアプローチでは不可能ですよね?
csalazar

6

正解は1つではありません。あなたが説明したように、それを行うにはいくつかの方法があります。私はファイルの命名スキームと、物事を異なるディレクトリに分割することの両方を行いました。

何かを別のディレクトリに分割する方がうまくいくように思えますが、それは私には少し明確に思えるので、それを重視します。

私にとってはより細かく見えるので、注釈を試してみるつもりはありません。これらの2種類のテストを同じファイルで本当に混合しますか?私はしません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.