2012-07-11 5 views
8

junit 4の "パラメータ化された"機能を使用していて、@parametersメソッドが@beforeclassメソッドの前に実行されていることに気付きました。 @parametersを介してテストケースに渡すパラメータは、@beforeclassメソッドで初期化されるコードに依存するため、これは私にとって問題を作り出しています。例えば@parametersメソッドは@beforeclassメソッドの前に実行されます

@RunWith(Parameterized.class) 
public class TestOtherClass { 

    String argument; 
    private static boolean initializeThis; 

    public TestOtherClass(String parameter) throws Exception { 
     argument=parameter; 
    } 

    @BeforeClass 
    public static void doSetup() { 
     System.out.println("Doing setup before class..."); 
     initializeThis=true; // true or false, based on some condition 
    } 

    @Test 
    public void otherTest() { 
     System.out.println("Other test: " + argument); 
    } 

    @Parameters 
    public static Collection<Object[]> getData(){ 
     System.out.println("Inside parameter"); 
     String addThis; 
     if(initializeThis) 
      addThis="adding true"; 
     else 
      addThis="adding false"; 

     Object[] para1 = new Object[]{"First parameter :: " + addThis}; 
     Object[] para2 = new Object[]{"Second parameter :: " + addThis}; 

     Collection<Object[]> classNames = new ArrayList<Object[]>(); 
     classNames.add(para1); 
     classNames.add(para2); 
     return classNames; 
    } 
} 

は今、私はテストケースを実行したときに、それは期待できないものです

Other test: First parameter :: adding false 
Other test: Second parameter :: adding false 

を印刷します(驚く)@BeforeClass方法でtrueに変数「initializeThis」を初期化するが、しています。
私の質問は、 @parametersの前に@beforeclassメソッドを実行する方法はありますか?これはjunit 4で行うことができますか?

+0

おそらく後で – Kirby

答えて

1

JUnitは、パラメータリストの項目ごとにRunnerを作成し、Runnerはテストメソッドをカプセル化したものです。したがって、@Parametersは常に@BeforeClassの前に実行されます。

ただし、@パラメータ化をAssumeと組み合わせることはできます。実行するかどうかに関わらず、すべてのパラメータをリストに必ず含めます。次に、テスト方法でinitializeThis値に対してテストするassumeTrue()を追加します。このことから

@RunWith(Parameterized.class) 
public class TestOtherClassAssume { 
    private final String argument; 
    private final boolean initializeThisTest; 
    private static boolean initializeThis; 

    @Parameters 
    public static Collection<Object[]> getData(){ 
    System.out.println("Inside parameter"); 

    return Arrays.asList(new Object[][] { 
     { false, "First" }, 
     { true, "Second" }, 
    }); 
    } 

    public TestOtherClassAssume(boolean initializeThisTest, String argument) { 
    this.initializeThisTest = initializeThisTest; 
    this.argument = argument; 
    } 

    @BeforeClass 
    public static void doSetup() { 
    System.out.println("Doing setup before class..."); 
    initializeThis = true; // true or false, based on some condition 
    } 

    @Test 
    public void otherTest() { 
    Assume.assumeTrue(initializeThis == initializeThisTest); 
    System.out.println("Other test: " + argument); 
    } 
} 

出力は次のようになります。

Inside parameter 
Doing setup before class... 
Other test: Second 
5

私の代わりに例えば@BeforeClass、の単なる古いJavaの静的{..}初期化子を使用します。

@RunWith(Parameterized.class) 
public class TestOtherClass { 

    String argument; 
    private static boolean initializeThis; 

    public TestOtherClass(String parameter) throws Exception { 
     argument=parameter; 
    } 

    static { 
     doSetup(); 
    } 

    // @BeforeClass 
    public static void doSetup() { 
     System.out.println("Doing setup before class..."); 
     initializeThis=true; // true or false, based on some condition 
    } 

    @Test 
    public void otherTest() { 
     System.out.println("Other test: " + argument); 
    } 

    @Parameters 
    public static Collection<Object[]> getData(){ 
     System.out.println("Inside parameter"); 
     String addThis; 
     if(initializeThis) 
      addThis="adding true"; 
     else 
      addThis="adding false"; 

     Object[] para1 = new Object[]{"First parameter :: " + addThis}; 
     Object[] para2 = new Object[]{"Second parameter :: " + addThis}; 

     Collection<Object[]> classNames = new ArrayList<Object[]>(); 
     classNames.add(para1); 
     classNames.add(para2); 
     return classNames; 
    } 
} 

だけ私は欠点これから継承したクラスは静的初期化子をオーバーライドすることはできませんが、この点では@BeforeClassはいくつかの自由を与えます。

0

ただし、これはTestSuitesでは機能しません。

@RunWith(Parameterized.class) 
public class TogglableParameterizedTest { 
    static boolean useAllParameters = false; 

    int parameter; 

    public TogglableParameterizedTest(int parameter) { 
     super(); 
     this.parameter = parameter; 
    } 
    @Parameters 
    public static Collection<Object[]> getTestParameters() { 
     List<Object[]> parameters = new ArrayList<Object[]>(); 
     if(useAllParameters) { 
      parameters.add(new Object[] { 1 }); 
      parameters.add(new Object[] { 2 }); 
      parameters.add(new Object[] { 3 }); 
     } 
     else { 
      parameters.add(new Object[] { 1 }); 
     } 
     return parameters; 
    } 
    @Test 
    public void test() { 
     System.out.println("parameter=" + parameter); 
    } 
} 

を考えると、これは動作しません:

@RunWith(Suite.class) 
@SuiteClasses({ TogglableParameterizedTest.class }) 
public class NonWorkingTestSuite1 { 

    @BeforeClass 
    public static void toggle() { 
     System.out.println("sets flag to late!"); 
    } 

} 

出力は

sets flag to late! 
parameter=1 

NORことです:

@RunWith(Suite.class) 
@SuiteClasses({ TogglableParameterizedTest.class }) 
public class NonWorkingTestSuite2 { 
    static { 
     System.out.println("sets flag still to late"); 
     TogglableParameterizedTest.useAllParameters = true; 
    } 
} 

出力が "= 1パラメータ" です。したがって、静的初期化子はまったく実行されません。 次の回避策が見つかりました。 は「スイート」を拡張し、そこに静的初期化子を挿入します。

public class TogglingSuite extends Suite { 

    static { 
     System.out.println("sets flag early enough!"); 
     TogglableParameterizedTest.useAllParameters = true; 
    } 

    public TogglingSuite(Class<?> klass, Class<?>[] suiteClasses) 
     throws InitializationError { 
     super(klass, suiteClasses); 
    } 

    public TogglingSuite(Class<?> klass, List<Runner> runners) 
     throws InitializationError { 
     super(klass, runners); 
    } 

    public TogglingSuite(Class<?> klass, RunnerBuilder builder) 
      throws InitializationError { 
     super(klass, builder); 
    } 

    public TogglingSuite(RunnerBuilder builder, Class<?> klass, 
      Class<?>[] suiteClasses) throws InitializationError { 
     super(builder, klass, suiteClasses); 
    } 

    public TogglingSuite(RunnerBuilder builder, Class<?>[] classes) 
      throws InitializationError { 
     super(builder, classes); 
    } 
} 

をし、あなたのテストスイートでそれを使用します。

@RunWith(TogglingSuite.class) 
@SuiteClasses({ TogglableParameterizedTest.class }) 
public class WorkingTestSuite { 

} 

出力は

sets flag early enough! 
parameter=1 
parameter=2 
parameter=3 

今では作品です。

4

これは古い質問ですが、最近同じ問題が発生しました。 @Parametersメソッドで@BeforeClassメソッドを呼び出すことで、最も明白な回避策の解決策が見つからないと私は思います。後者は静的であり、テストが実行される前に1回だけ実行されます。したがって、そのようにアノテーションされていないにもかかわらず、すべての目的と目的のために@BeforeClassメソッドがあります。詳細はここで見つけることができます:http://feraldeveloper.blogspot.co.uk/2013/12/beforeclass-and-parametrized-junit-tests.html

+0

テストは '@ClassRuleのpublic static TemporaryFolderフォルダ=新しいTemporaryFolder(のようなものを必要とする場合、残念ながら、これは動作しません)フィールドを取得できるパラメータのためのサプライヤー機能を渡します;' @Parameters(https://github.com/junit-team/junit4/issues/527)でアノテーションされたメソッドの後でClassRuleさえ初期化されるため、 –

関連する問題