JUnit 4で現在実行中のテストの名前を取得します


240

JUnit 3では、次のように現在実行中のテストの名前を取得できます。

public class MyTest extends TestCase
{
    public void testSomething()
    {
        System.out.println("Current test is " + getName());
        ...
    }
}

「現在のテストはtestSomethingです」と出力されます。

JUnit 4でこれを行うためのすぐに使用できる簡単な方法はありますか?

背景:明らかに、テストの名前だけを印刷する必要はありません。テストと同じ名前のリソースに格納されているテスト固有のデータをロードしたい。ご存知のとおり、構成に関する規約などです。


上記のコードはJUnit 4で何を提供しますか?
トカゲに請求する

5
JUnit 3テストは、getName()が定義されているTestCaseを拡張します。JUnit 4テストは基本クラスを拡張しないため、getName()メソッドはまったくありません。
デイブ・レイ

番号付けされたテストケースのみを提供するパラメーター化されたランナーを使用しているため、テスト名を<b>設定</ b>したいという同様の問題があります。
Volker Stolz、

TestまたはTestWatcherを使用した素敵なソリューション...これが必要になるかどうか(大声で)疑問に思っていますか?Gradleが提供するタイミング出力チャートを見ると、テストの実行が遅いかどうかを確認できます。テストが動作する順序を知る必要はありません...?
マイクげっ歯類

回答:


378

JUnit 4.7は、TestName-Ruleを使用しているように見えるこの機能を追加しました。これはメソッド名を取得するように見えます:

import org.junit.Rule;

public class NameRuleTest {
    @Rule public TestName name = new TestName();

    @Test public void testA() {
        assertEquals("testA", name.getMethodName());
    }

    @Test public void testB() {
        assertEquals("testB", name.getMethodName());
    }
}

4
TestNameは@beforeでは使用できないことにも注意してください:(参照:old.nabble.com/…–
jm。

41
どうやら新しいバージョンのJUnitが@Rule以前に実行されたよう@Beforeです-私はJUnitを初めて使用しTestName、問題@Beforeなく依存しています。
MightyE 2010


2
パラメータ化されたテストを使用している場合、 "name.getMethodName()"は{testA [0]、testA [1]など}を返すため、次のようなものを使用します:assertTrue(name.getMethodName()。matches( "testA(\ [\ \ d \])? "));
Legna

2
@DuncanJones提案された代替案が「より効率的」なのはなぜですか?
ステファン

117

JUnit 4.9.x以降

JUnit 4.9以降、このTestWatchmanクラスは廃止され、次のTestWatcher呼び出しが行われます。

@Rule
public TestRule watcher = new TestWatcher() {
   protected void starting(Description description) {
      System.out.println("Starting test: " + description.getMethodName());
   }
};

注:包含クラスを宣言する必要がありますpublic

JUnit 4.7.x-4.8.x

次のアプローチは、クラス内のすべてのテストのメソッド名を出力します。

@Rule
public MethodRule watchman = new TestWatchman() {
   public void starting(FrameworkMethod method) {
      System.out.println("Starting test: " + method.getName());
   }
};

1
@takacsotそれは驚くべきことです。これについて新鮮な質問を投稿して、ここのリンクにpingしてください。
ダンカンジョーンズ

publicフィールドを使用する理由
Raffi Khatchadourian 2016年


16

JUnit 5以降

JUnit 5では、注入TestInfoしてテストメソッドに提供するテストメタデータを簡素化できます。例えば:

@Test
@DisplayName("This is my test")
@Tag("It is my tag")
void test1(TestInfo testInfo) {
    assertEquals("This is my test", testInfo.getDisplayName());
    assertTrue(testInfo.getTags().contains("It is my tag"));
}

より参照してください:JUnitの5ユーザーガイドTestInfoのJavadocを


9

代わりにこれを試してください:

public class MyTest {
        @Rule
        public TestName testName = new TestName();

        @Rule
        public TestWatcher testWatcher = new TestWatcher() {
            @Override
            protected void starting(final Description description) {
                String methodName = description.getMethodName();
                String className = description.getClassName();
                className = className.substring(className.lastIndexOf('.') + 1);
                System.err.println("Starting JUnit-test: " + className + " " + methodName);
            }
        };

        @Test
        public void testA() {
                assertEquals("testA", testName.getMethodName());
        }

        @Test
        public void testB() {
                assertEquals("testB", testName.getMethodName());
        }
}

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

Starting JUnit-test: MyTest testA
Starting JUnit-test: MyTest testB

注:テストがTestCaseのサブクラスの場合、これは機能しません。テストは実行されますが、@ Ruleコードは実行されません。


3
模範のまさにそのとき、あなたのノートのために神はあなたを祝福します。
user655419

「これは機能しません」-適例-キュウリは@Ruleアノテーションを無視します
Benjineer

8

SLF4J(Simple Logging Facade for Java)の使用を検討してください。パラメーター化されたメッセージを使用することで、きちんとした改善が得られます。SLF4JをJUnit 4ルール実装と組み合わせると、より効率的なテストクラスのロギングテクニックを提供できます。

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingTest {

  @Rule public MethodRule watchman = new TestWatchman() {
    public void starting(FrameworkMethod method) {
      logger.info("{} being run...", method.getName());
    }
  };

  final Logger logger =
    LoggerFactory.getLogger(LoggingTest.class);

  @Test
  public void testA() {

  }

  @Test
  public void testB() {

  }
}

6

複雑な方法は、org.junit.runners.BlockJUnit4ClassRunnerをサブクラス化して独自のランナーを作成することです。

その後、次のようなことができます:

public class NameAwareRunner extends BlockJUnit4ClassRunner {

    public NameAwareRunner(Class<?> aClass) throws InitializationError {
        super(aClass);
    }

    @Override
    protected Statement methodBlock(FrameworkMethod frameworkMethod) {
        System.err.println(frameworkMethod.getName());
        return super.methodBlock(frameworkMethod);
    }
}

次に、各テストクラスに対して、@ RunWith(NameAwareRunner.class)アノテーションを追加する必要があります。あるいは、毎回覚えておきたくない場合は、そのアノテーションをTestスーパークラスに置くこともできます。もちろん、これによりランナーの選択が制限されますが、それでも問題はありません。

また、現在のテスト名をRunnerからフレームワークに取得するには、少しカンフーがかかる場合がありますが、これで少なくとも名前がわかります。


少なくとも概念的には、この考えは私にはかなり簡単に思えます。私のポイントは、私はそれを複雑だとは思いません。
user98761

「on a Test superclass ...」-恐ろしい継承ベースのデザインパターンはもう必要ありません。これはまさにJUnit3です!
2013

3

JUnit 4には、テストケースの独自の名前を取得するための、すぐに使用できるメカニズムはありません(セットアップ時とティアダウン時を含む)。


1
スタックを検査する以外に、すぐに使えるメカニズムはありますか?
デイブ・レイ

4
以下の答えが与えられた場合はそうではありません!多分誰かに正しい答えを割り当てますか?
Toby 2013

3
String testName = null;
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
for (int i = trace.length - 1; i > 0; --i) {
    StackTraceElement ste = trace[i];
    try {
        Class<?> cls = Class.forName(ste.getClassName());
        Method method = cls.getDeclaredMethod(ste.getMethodName());
        Test annotation = method.getAnnotation(Test.class);
        if (annotation != null) {
            testName = ste.getClassName() + "." + ste.getMethodName();
            break;
        }
    } catch (ClassNotFoundException e) {
    } catch (NoSuchMethodException e) {
    } catch (SecurityException e) {
    }
}

1
私は彼が解決策を提示したかっただけだと主張できます..なぜ反対票を投じたのかわかりません... @downvoter:少なくとも、少なくとも有用な情報を追加してください..
Victor

1
@skaffman私たちは皆、代替ソリューションの全範囲を見たいと思っています。これは私が探しているものに最も近いものです:テストクラスで直接テスト名を取得するのではなく、テスト中に使用されるクラス(たとえば、ロガーコンポーネントのどこか)で取得します。そこで、テスト関連のアノテーションは機能しなくなりました。
ダニエルアルダー

3

前のコメントに基づいてさらに検討した結果、JUnitテストメソッドで使用できるTestWatherの拡張機能を作成しました。

public class ImportUtilsTest {
    private static final Logger LOGGER = Logger.getLogger(ImportUtilsTest.class);

    @Rule
    public TestWatcher testWatcher = new JUnitHelper(LOGGER);

    @Test
    public test1(){
    ...
    }
}

次はテストヘルパークラスです。

public class JUnitHelper extends TestWatcher {
private Logger LOGGER;

public JUnitHelper(Logger LOGGER) {
    this.LOGGER = LOGGER;
}

@Override
protected void starting(final Description description) {
    LOGGER.info("STARTED " + description.getMethodName());
}

@Override
protected void succeeded(Description description) {
    LOGGER.info("SUCCESSFUL " + description.getMethodName());
}

@Override
protected void failed(Throwable e, Description description) {
    LOGGER.error("FAILURE " + description.getMethodName());
}
}

楽しい!


こんにちは。ImportUtilsTestエラーが発生しました。ロガークラスのようです。詳細情報はありますか?ありがとう
Sylhare

1
名前付きクラスは、JUnitテストクラスの単なる例であり、JUnitHelperのユーザーです。使用例を修正します。
Csaba Tenkes

ああ、今、私は馬鹿げていると感じています。どうもありがとう!;)
Sylhare

1
@ClassRule
public static TestRule watchman = new TestWatcher() {
    @Override
    protected void starting( final Description description ) {
        String mN = description.getMethodName();
        if ( mN == null ) {
            mN = "setUpBeforeClass..";
        }

        final String s = StringTools.toString( "starting..JUnit-Test: %s.%s", description.getClassName(), mN );
        System.err.println( s );
    }
};

0

テストメソッド名をテストデータセットから分離することをお勧めします。リソースからテストデータのセットをロード/キャッシュするDataLoaderFactoryクラスをモデル化し、テストケースで、テストケースのテストデータのセットを返すインターフェイスメソッドを呼び出します。テストメソッド名にテストデータを関連付けると、テストデータは1回しか使用できないと想定されます。ほとんどの場合、同じテストデータを複数のテストで使用して、ビジネスロジックのさまざまな側面を検証することをお勧めします。


0

これを使用Slf4jしてこれを達成できますTestWatcher

private static Logger _log = LoggerFactory.getLogger(SampleTest.class.getName());

@Rule
public TestWatcher watchman = new TestWatcher() {
    @Override
    public void starting(final Description method) {
        _log.info("being run..." + method.getMethodName());
    }
};

0

JUnit 5ではTestInfo、JUnit 4のTestNameルールのドロップイン代替として機能します。

ドキュメントから:

TestInfoは、現在のテストまたはコンテナに関する情報を@ Test、@ RepeatedTest、@ ParameterizedTest、@ TestFactory、@ BeforeEach、@ AfterEach、@ BeforeAll、および@AfterAllメソッドに挿入するために使用されます。

現在実行されているテストのメソッド名を取得するには、String TestInfo.getDisplayName()およびの 2つのオプションがあります Method TestInfo.getTestMethod()

現在のテストメソッドの名前のみを取得 TestInfo.getDisplayName()するには、テストメソッドのデフォルトの表示名がであるため、十分ではない場合がありますmethodName(TypeArg1, TypeArg2, ... TypeArg3)
でメソッド名を複製する@DisplayName("..")必要はありません。

別の方法としてTestInfo.getTestMethod()Optional<Method>オブジェクトを返すものを使用でき ます。
検索メソッドがテストメソッド内で使用されている場合、Optionalラップされた値をテストする必要すらありません。

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Test;

@Test
void doThat(TestInfo testInfo) throws Exception {
    Assertions.assertEquals("doThat(TestInfo)",testInfo.getDisplayName());
    Assertions.assertEquals("doThat",testInfo.getTestMethod().get().getName());
}

0

ExtensionContextを介したJUnit 5

利点:

ExtensionContextオーバーライドすることで、の追加機能を利用できますafterEach(ExtensionContext context)

public abstract class BaseTest {

    protected WebDriver driver;

    @RegisterExtension
    AfterEachExtension afterEachExtension = new AfterEachExtension();

    @BeforeEach
    public void beforeEach() {
        // Initialise driver
    }

    @AfterEach
    public void afterEach() {
        afterEachExtension.setDriver(driver);
    }

}
public class AfterEachExtension implements AfterEachCallback {

    private WebDriver driver;

    public void setDriver(WebDriver driver) {
        this.driver = driver;
    }

    @Override
    public void afterEach(ExtensionContext context) {
        String testMethodName = context.getTestMethod().orElseThrow().getName();
        // Attach test steps, attach scsreenshots on failure only, etc.
        driver.quit();
    }

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