LoginSignup
0
0

More than 3 years have passed since last update.

TestNG で実行中のテストメソッドをリスナで可視化する

Posted at

TestNG あるある「ここはどこ?」

コンソール上で TestNG のテストをふつうに流すと,どのテストメソッドを実行中かといった情報を何も出してくれません.
全部のテストがすんなり流れてくれるならそれで構わないのですが,

% mvn clean test
[INFO] Scanning for projects...
(中略)
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running TestSuite

↑ たまにこんな表示のまま固まってしまって,どのテストでハングしているかもわからず途方にくれることがあります.

というわけで,そんな困ったことにならないように,TestNG でどのテストを実行中かをコンソール上に出力させる方法を紹介します.
対処後に出力されるログのイメージはこんな感じです:

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running TestSuite
[CustomTestListener] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 0, 0)
[CustomTestListener] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 1, 1)

この記事では,以下の 3 つの方法を紹介します.

  • 方法 1: テストメソッドにログを直接仕込む
  • 方法 2: テストクラスの @BeforeMethod メソッドにログを仕込む
  • 方法 3: リスナを追加して onTestStart メソッドにログを仕込む (← この記事のメイン)

サンプルコード

この記事で使用するサンプルコードは GitHub に置いてあります.

方法 1: テストメソッドにログを直接仕込む

テストメソッドそのものに直接ログを仕込むという,素朴で安直な方法です.
ログを出したいメソッドが限られている場合はいいですが,数が多いと大変なことに...

public class CalcTest {
    @Test(dataProvider = "testAdd")
    public void testAdd(int x, int y, int expected) {
        // テストメソッドの情報をログに出力
        LOGGER.info(String.format(
        "Running: com.example.calc.test.CalcTest#testAdd(%d, %d, %d)", x, y, expected));

        Calc calc = new Calc();
        assertEquals(calc.add(x, y), expected);
    }
    // ...
}
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running TestSuite
[CalcTest] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 0, 0)
[CalcTest] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 1, 1)

方法 2: テストクラスの @BeforeMethod メソッドにログを仕込む

テストクラスに @BeforeMethod アノテーションを付けたメソッドを定義し,その中にログを仕込みます.
テストクラスをちょこっといじれば済むので,とっかかりやすくわかりやすいリーズナブルな方法ではないでしょうか.

import org.testng.annotations.BeforeMethod;

public class CalcTest {
    @BeforeMethod
    public void beforeMethod(Method method, Object[] data) {
        // テストメソッドの情報をログに出力
        LOGGER.info(String.format(
            "Running: %s#%s(%s)",
            method.getDeclaringClass().getCanonicalName(),
            method.getName(),
            Arrays.stream(data).map(x -> x.toString()).collect(Collectors.joining(", "))));
    }
    // ...
}
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running TestSuite
[CalcTest] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 0, 0)
[CalcTest] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 1, 1)

方法 3: リスナを追加して onTestStart メソッドにログを仕込む

TestNG のリスナを追加して,リスナの onTestStart メソッドでログを仕込むという方法です.
リスナを設定するという手間はありますが,設定がグローバルに効くので,ターゲットのテストメソッドが多い場合とかに有効です.
また,テストクラスをいじらなくても済むので,テストセットを変更できない場合 (TCK を実行する場合とか) にも役に立ちます.

TestNG のリスナは,ITestListener インタフェースを実装した以下のようなクラスとして用意します.

import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class CustomTestListener implements ITestListener {
    private static final Logger LOGGER = Logger.getLogger(CustomTestListener.class);

    public void onTestStart(ITestResult result) {
        // テストメソッドの情報をログに出力
        LOGGER.info(String.format(
            "Running: %s#%s(%s)",
            result.getMethod().getTestClass().getName(),
            result.getMethod().getMethodName(),
            Arrays.stream(result.getParameters()).map(x -> x.toString()).collect(Collectors.joining(", "))));
    }

    public void onTestSuccess(ITestResult result) { }
    public void onTestFailure(ITestResult result) { }
    public void onTestSkipped(ITestResult result) { }
    public void onTestFailedButWithinSuccessPercentage(ITestResult result) { }
    public void onStart(ITestContext context) { }
    public void onFinish(ITestContext context) { }
}

また,リスナを TestNG に登録するために,testng.xml を編集するか,テストクラスに @Listeners アノテーションを指定します.
testng.xml でリスナを登録する場合は,以下のように書きます.

<suite>
    <listeners>
        <listener class-name="com.example.calc.test.util.CustomTestListener"/>
    </listeners>
   <!-- ... -->
</suite>

テストクラスに @Listeners アノテーションを指定する場合は,以下のように書きます.

import org.testng.annotations.Listeners;

@Listeners({ CustomTestListener.class })
public class CalcTest {
    // ...
}

期待されるログの出力はこんな感じです.

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running TestSuite
[CustomTestListener] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 0, 0)
[CustomTestListener] [INFO] Running: com.example.calc.test.CalcTest#testAdd(0, 1, 1)

まとめ

TestNG で実行中のテストを可視化する方法を紹介しました.
この記事で紹介したように方法はいろいろあるので,ケースバイケースで試してみてください!

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0