2009-08-05 6 views
12

私たちはJUnit 4を使ってテストしています:クラスはTestCaseのサブクラスではなく、@Testと注釈されたパブリックメソッドを持っています。我々は、多くの@Testメソッドを持つ1つのファイルを持っています。 JUnitの3のためにこのレシピのスタイルで、コマンドラインからAntを介して、それらのサブセットを実行できるようにするとよいでしょう:私は考えるしようとしてきたJUnit @Testメソッドのサブセットを実行しています

ant runtest -Dtest=MyTest -Dtests=testFoo,testBar 

http://today.java.net/pub/a/today/2003/09/12/individual-test-cases.html

Javaリフレクションなどでこれを実現する方法@Testメソッドを「隠す」方法や実行時にアノテーションを削除する方法はないようですので、唯一のオプションはClassLoaderのdefineClassメソッドを使用しているようです。

P.S.この状況で正しいことはファイルを分割することですが、選択肢はありますか?

お時間をいただきありがとうございます。

答えて

10

guerdaの解答は良いです。

@RunWith(FilteredRunner.class) 
public class MyTest { 
import org.junit.runner.manipulation.Filter; 
import org.junit.runner.Description; 

public final class AntCLFilter extends Filter { 
    private static final String TEST_CASES = "tests"; 
    private static final String ANT_PROPERTY = "${tests}"; 
    private static final String DELIMITER = "\\,"; 
    private String[] testCaseNames; 

    public AntCLFilter() { 
     super(); 
     if (hasTestCases()) testCaseNames = getTestCaseNames(); 
    } 

    public String describe() { 
     return "Filters out all tests not explicitly named in a comma-delimited list in the system property 'tests'."; 
    } 

    public boolean shouldRun(Description d) { 
     String displayName = d.getDisplayName(); 
     // cut off the method name: 
     String testName = displayName.substring(0, displayName.indexOf('(')); 
     if (testCaseNames == null) return true; 

     for (int i = 0; i < testCaseNames.length; i++) 
      if (testName.equals(testCaseNames[i])) 
       return true; 
     return false; 
    } 

    /** 
    * Check to see if the test cases property is set. Ignores Ant's 
    * default setting for the property (or null to be on the safe side). 
    **/ 
    public static boolean hasTestCases() { 
     return 
      System.getProperty(TEST_CASES) == null || 
      System.getProperty(TEST_CASES).equals(ANT_PROPERTY) ? 
      false : true; 
    } 

    /** 
    * Create a List of String names of test cases specified in the 
    * JVM property in comma-separated format. 
    * 
    * @return a List of String test case names 
    * 
    * @throws NullPointerException if the TEST_CASES property 
    * isn't set 
    **/ 
    private static String[] getTestCaseNames() { 

     if (System.getProperty(TEST_CASES) == null) { 
      throw new NullPointerException("Test case property is not set"); 
     } 

     String testCases = System.getProperty(TEST_CASES); 
     String[] cases = testCases.split(DELIMITER); 

     return cases; 
    } 
} 

import org.junit.internal.runners.*; 
import org.junit.runner.manipulation.Filter; 
import org.junit.runner.manipulation.NoTestsRemainException; 

public class FilteredRunner extends TestClassRunner { 

    public FilteredRunner(Class<?> clazz) throws InitializationError { 
     super(clazz); 
     Filter f = new AntCLFilter(); 
     try { 
      f.apply(this); 
     } catch (NoTestsRemainException ex) { 
      throw new RuntimeException(ex); 
     } 
    } 
} 

は、その後私は私のテストクラスを注釈付き:ここで私は(それは私が前にリンクルークFranclのレシピ、のミックスだ、と私はネット上で見たいくつかの他のものは)やってしまったものです

と私のアリビルドファイルに次のように置く:

<target name="runtest" 
     description="Runs the test you specify on the command line with -Dtest=" 
     depends="compile, ensure-test-name"> 
    <junit printsummary="withOutAndErr" fork="yes"> 
     <sysproperty key="tests" value="${tests}" /> 
     <classpath refid="classpath" /> 
     <formatter type="plain" usefile="false" /> 
     <batchtest> 
      <fileset dir="${src}"> 
       <include name="**/${test}.java" /> 
      </fileset> 
     </batchtest> 
    </junit> 
</target> 

がキーラインがsyspropertyタグであること。

し、必要に応じて、今私は

ant runtest -Dtest=MyTest -Dtests=testFoo,testBar 

を実行することができます。 JUnit4ClassRunnerのサブクラスである4.4ではJUnit 4.1で動作し、4.5以降ではBlockJUnit4ClassRunnerのサブクラスで動作します。

+0

OK、それははるかにエレガントです私の解決策よりも:) – guerda

+0

私は数日間この同じ(または少なくとも非常に似たような)問題に苦労してきました。 Powermockで独自の@RunWith(PowermockRunner.class)アノテーションが必要なFilteredRunnerを使用する場合はどうなりますか? –

+0

偉大な答えですが、今は時代遅れです。私はTestClassRunnerの代わりにBlockJUnit4ClassRunnerを使う必要があると思います。 – Illidanek

8

自分でTestClassMethodsRunnerを作成してください(これは文書化されていないか、今は見つかりません)。
TestClassMethodsRunnerはすべてのテストケースを実行し、フィルタリングされたTestClassMethodsRunnerを設定できます。

あなたがしなければならないのは、TestMethodRunner createMethodRunner(Object, Method, RunNotifier)メソッドを上書きすることだけです。これは単純なハックソリューションです。このテストランナーで

public class FilteredTestRunner extends TestClassMethodsRunner { 

    public FilteredTestRunner(Class<?> aClass) { 
     super(aClass); 
    } 

    @Override 
    protected TestMethodRunner createMethodRunner(Object aTest, Method aMethod, RunNotifier aNotifier) { 
     if (aTest.getClass().getName().contains("NOT")) { 
      return new TestMethodRunner(aTest, aMethod, aNotifier, null) { 
       @Override 
       public void run() { 
        //do nothing with this test. 
       } 
      }; 
     } else { 
      return super.createMethodRunner(aTest, aMethod, aNotifier); 
     } 
    } 

} 

、あなたは文字列「NOT」を含まないすべてのテストを実行します。他のものは無視されます:)あなたのTestRunnerクラスの@RunWithアノテーションをテストに追加してください。

@RunWith(FilteredTestRunner.class) 
public class ThisTestsWillNOTBeExecuted { 
    //No test is executed. 
} 

@RunWith(FilteredTestRunner.class) 
public class ThisTestsWillBeExecuted { 
    //All tests are executed. 
} 

createMethodRunner方法では、実行するか、新しいのcriteriasを導入しなければならないテストのリストに対して、現在のテストを確認することができます。

これで幸運を祈る!

もっと良い解決策のヒントがありがとう!

12

JUnit 4.8以降、この問題を解決するための@Category注釈があります。

+2

@Categoryはかなりクールですが、あなたがすでにスイートを構築している場合に限ります。記事の末尾には、誰のテスト環境にも適合しないと書かれているので。彼らは間違いなく指摘する価値がある、いくつかの幸運な人々のために、これは完全に彼らの問題を解決します。 –

+2

そして、Surefire 2.11以降では、-Dグループを使用してスイートを構築せずにカテゴリ別にテストを選択することができます。私はこの改善のおかげで先週、多くのテストスイートを削除できてうれしく思いました! (Maven SurefireプラグインのパラメータはTestNGについてのみ記載されていますが、2.11はJUnitでも動作します) –

+0

そのサイトはダウンしているようです... –

1

あなたが唯一のテストメソッドを実行する必要がある一般的な場合のための簡単な方法は、カスタムRunnerまたはFilterを作成する手間を経由せず、あります:

public class MyTestClass { 

    public static void main(final String[] args) throws Exception { 
    final JUnitCore junit = new JUnitCore(); 
    final String singleTest = // Get the name of test from somewhere (environment, system property, whatever you want). 
    final Request req; 
    if (singleTest != null) { 
     req = Request.method(MyTestClass.class, singleTest); 
    } else { 
     req = Request.aClass(MyTestClass.class); 
    } 
    final Result result = junit.run(req); 
    // Check result.getFailures etc. 
    if (!result.wasSuccessful()) { 
     System.exit(1); 
    } 
    } 

    // Your @Test methods here. 

} 
関連する問題