クラスの前のJUnit(非静的)


84

Junitにテストファイルで関数を1回実行させるためのベストプラクティスはありますか?また、静的であってはなりません。

@BeforeClass非静的関数のように?

これが醜い解決策です:

@Before void init(){
    if (init.get() == false){
        init.set(true);
        // do once block
    }
}

これは私がやりたくないことであり、統合されたjunitソリューションを探しています。


さて、私はテストファイルとベーステストファイルの非常に大きな階層を持っています、私は子テストクラスでこのアクションをオーバーライドする可能性が必要です。
ローマ

1
多くのパラメータ化されたテストの最初のものだけがログインを実行する必要があるという同じ問題がありました。
dokaspar 2012年

5
プレーンなJUnitで機能する「醜い」ソリューションは、ティアリングテストを考慮に入れていないことに注意してください。
eskatos 2013年

回答:


22

静的初期化子を1回の初期化用にセットアップする必要がなく、JUnitの使用にこだわらない場合は、TestNGを参照してください。TestNGは、すべてアノテーションを使用して、さまざまな構成オプションを使用した非静的な1回限りの初期化をサポートします。

TestNGでは、これは次と同等です。

@org.testng.annotations.BeforeClass
public void setUpOnce() {
   // One time initialization.
}

分解については、

@org.testng.annotations.AfterClass
public void tearDownOnce() {
   // One time tear down.
}

JUnit 4@Beforeと同等のTestNGの@After場合@BeforeMethod@AfterMethodそれぞれとを使用できます。


41

単純なifステートメントもかなりうまく機能しているようです。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {

    public static boolean dbInit = false;

    @Autowired
    DbUtils dbUtils;

    @Before
    public void setUp(){

        if(!dbInit){

            dbUtils.dropTables();
            dbUtils.createTables();
            dbInit = true;

        }
    }

 ...

1
素晴らしくてシンプル!しかし、これを単純に適応させ@AfterClassて、すべてのテストが実行された後に破棄される非静的な同等物を作成する方法を見つけることができませんか?
スティーブチェンバーズ

1
継承を使用するテストクラスで機能するこのメソッドの更新については、ここを参照してください。
スティーブチェンバーズ2015年

36

空のコンストラクターを使用するのが最も簡単な解決策です。拡張クラスのコンストラクターは引き続きオーバーライドできます。

しかし、それはすべての継承で最適ではありません。そのため、JUnit4は代わりに注釈を使用します。

もう1つのオプションは、factory / utilクラスにヘルパーメソッドを作成し、そのメソッドに作業を任せることです。

Springを使用している場合は、@TestExecutionListenersアノテーションの使用を検討する必要があります。このテストのようなもの:

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({CustomTestExecutionListener.class, 
     DependencyInjectionTestExecutionListener.class})
@ContextConfiguration("test-config.xml")
public class DemoTest {

SpringにAbstractTestExecutionListenerは、たとえば、オーバーライドできるこの空のメソッドが含まれています。

public void beforeTestClass(TestContext testContext) throws Exception {
    /* no-op */
}

注:DependencyInjectionTestExecutionListenerカスタムを追加する際に見落としたり見逃したりしないでくださいTestExecutionListeners。そうした場合、すべての自動配線はになりますnull


+1この手法は、DbUnitを使用し、クラスごとに1回だけデータセットをロードする場合の問題を解決しました
Brad

+1これは完璧です... Springの古代バージョンに縛られていない人々にとって。:(
マイクミラー

1
これbeforeTestClass()は、コンテキストが初期化される前または後に呼び出されますか?
DIMS

@Dims後のコンテキストが初期化
アナンドRockzz

7

@BeforeAllMethods/@AfterAllMethodsアノテーションを簡単に使用して、インスタンスコンテキスト(非静的)内でメソッドを実行します。ここで、挿入されたすべての値が使用可能になります。

このための特別なテストライブラリがあります:

https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0

https://bitbucket.org/radistao/before-after-spring-test-runner/

唯一の制限:Springテストでのみ機能します。

(私はこのテストライブラリの開発者です)


0

試したことはありませんが、引数のないコンストラクターを作成して、そこから関数を呼び出すことができますか?


これは機能します。問題は、この基本テストクラスを拡張するクラスでこのアクションをオーバーライドする可能性が必要なことです
ローマ

@ローマ:ああ、なるほど。これをあなたの投稿に追加してください。このコメントは物事をより明確にします。
ローマ

コンストラクターは、テストケースが存在する回数だけ呼び出されます。テストメソッドごとに、新しいTestクラスオブジェクトが作成されます。したがって、コンストラクターを使用することはここでは解決策ではありません
manikanta 2011

また、これは、すでに構築されているオブジェクトに依存する依存性注入では機能しません。
マイクミラー

0

この記事では、この問題に対する2つの非常に優れた解決策について説明しています。

  1. カスタムランナーを使用した「クリーンな」junit(インターフェイスを使用しますが、@ BeforeInstanceなどのカスタムアノテーションを使用して拡張できます)
  2. 前にEspenが述べたように春の実行リスナー。

0

更新:以下の提案に欠陥がある理由については、Cherryのコメントを参照してください。(コメントは、これが機能しない理由について他の人に役立つ情報を提供する可能性があるため、削除するのではなく、ここに回答を保持しています。)


依存性注入(Springなど)を使用する場合に検討する価値のあるもう1つのオプションは@PostConstructです。これにより、依存性の注入が完了することが保証されますが、コンストラクターではそうではありません。

@PostConstruct
public void init() {
    // One-time initialization...
}


7
Junitテストの場合の非常に悪い解決策。JUnitは、テストメソッドを実行するたびにテストクラスインスタンスを作成します。したがって、クラスに6つのテストメソッドがある場合、クラスコンストラクター@Before@Afterメソッドは6回呼び出されます。したがって、このコンテキストで@PostConstructは、@Before注釈のように動作します。簡単にテストできます。2つのテストメソッドをテストクラスに入れ、追加して@PostConstruct public void init() {System.out.println("started");}、印刷された回数をログに確認します。
チェリー

情報については、JUnitが実行ごとにインスタンスを作成することについての上記のコメントで説明されていることを確認するJUnitのドキュメントに出くわしました@Test「メソッドを実行するには、JUnitは最初にクラスの新しいインスタンスを作成し、次にアノテーション付きメソッドを呼び出します。」
スティーブチェンバーズ

-2

使用するだけ@BeforeClassです:

@BeforeClass
public static void init() {
}

init各テストは別々のインスタンスで実行されるため、非静的であることは意味がありません。インスタンスinit上で実行されるには、すべてのテストのインスタンスと一致しません。

非静的にしたい唯一の理由は、サブクラスでオーバーライドすることですが、静的メソッドでもこれを行うことができます。同じ名前を使用するだけで、サブクラスinitメソッドのみが呼び出されます。


2
この質問全体は、非静的な方法でそれを行う可能性についてです。これは、クラスにいくつかのインスタンス変数が必要な場合に必要です。
Simon Forsberg 2017

@SimonForsbergはい、質問はXYの問題だと言っています。作戦は、問題が子クラスの行動を無効にしていると述べた。例でインスタンス変数が必要な場合は、別のことを提案するかもしれません。
fgb 2017

:このコメントを参照してくださいstackoverflow.com/questions/2825615/...
サイモン・フォースバーグ

@SimonForsbergそれは私が話していたコメントです。それはどうですか?
fgb 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.