Otaku, Cedric's weblog: Advanced parallel testing with TestNG and data providers
TestNGのデータプロバイダを利用してのより進んだ並列テスト
TestNGは別々のスレッドでテストを実行できる。スレッドプールサイズとタイムアウトを設定するだけでいい。TestNGがあとのことはやってくれる。たとえば、次のようなクラスを考えてみよう。スレッドプールのサイズは2と設定して呼び出してみる。
@Test public class A { public void g1() { log("g1"); } public void g2() { log("g2"); } public void g3() { log("g3"); } public void g4() { log("g4"); } }
結果はこうなる。
Thread:9 g4()
Thread:8 g2()
Thread:8 g3()
Thread:9 g1()
この結果からわかるように、TestNGは2つのスレッドのプールを生成し、すべてのテストメソッドを利用できるスレッドに振り分ける。スレッド戦略を設定することもできる(「テストメソッドごとに別のスレッドにする」「テストクラスごとに別のスレッドにする」など)し、各スレッドごとにタイムアウトを設定することもできる。
TestNGの有名な機能としてデータプロバイダもある。メソッドとデータプロバイダを2つずつ前のテストクラスに追加する。
@DataProvider() public Object[][] dp1() { return new Object[][] { new Object[] { 1 }, new Object[] { 2 }, new Object[] { 3 }, new Object[] { 4 }, }; } @Test(dataProvider = "dp1") public void f1(Integer n) { log("f1", n); } @DataProvider public Object[][] dp2() { return new Object[][] { new Object[] { 11 }, new Object[] { 12 }, new Object[] { 13 }, new Object[] { 14 }, }; } @Test(dataProvider = "dp2") public void f2(Integer n) { log("f2", n); }
f1()は1、2、3、4と、f2()は11、12、13、14とパラメータが渡されて呼び出される。
実行するとこうなる(テストメソッドごとに色を変えた)。
Thread:9 g4()
Thread:8 g3()
Thread:9 g2()
Thread:8 f1(1)
Thread:9 f2(11)
Thread:9 f2(12)
Thread:9 f2(13)
Thread:8 f1(2)
Thread:9 f2(14)
Thread:8 f1(3)
Thread:9 g1()
Thread:8 f1(4)
まだスレッドプールのサイズは2で実行しているが、データプロバイダを使っている2つのメソッド(f1()とf2())は同一のスレッドで順番に呼び出されている。言い換えると、f1()は1つのスレッドで呼び出され、データプロバイダから値(1、2、3、4)をすべて受け取るまで同一スレッドに残ったままである。同様にf2()も値(11、12、13、14)を受け取るまで残っている。
データプロバイダへのマルチスレッド対応はTestNGでもっとも望まれていた機能だった。この実装が終わりTestNGの次のリリースに含められることをうれしく思っている。
スレッドプールでデータプロバイダを実行させるには、アノテーションのparallel属性を使う。
@DataProvider(parallel = true) public Object[][] dp2() {
データプロバイダは別のスレッドで実行されるため、テストメソッドのスレッドとは異なるスレッドとなる。テストのスレッドプールを2、データプロバイダのスレッドプールを3に設定して先ほどのテストを実行するとこうなる。
Thread:9 g4()
Thread:8 g3()
Thread:8 g2()
Thread:9 f1(1)
Thread:10 f2(11)
Thread:11 f2(12)
Thread:12 f2(13)
Thread:9 f1(2)
Thread:12 f2(14)
Thread:9 f1(3)
Thread:9 f1(4)
Thread:8 g1()
この実行だとg*メソッドとf1()はテストのスレッドプールで実行している(f1()はデータプロバイダを使っていてparallel=trueを指定していないので、テストのスレッドプールを使っていることを思い出してほしい)。ここで目新しいことはf2()の4角メソッド呼び出しが3つの異なるスレッド(スレッド10、11、12)で起こっていることだ。これら3つのスレッドはデータプロバイダのスレッドプールにある。そのサイズは3に設定している。
同様に残りのデータプロバイダもparallelにしよう。
@DataProvider(parallel = true) public Object[][] dp1() {
こうなる。
Thread:9 g4()
Thread:8 g3()
Thread:8 g2()
Thread:10 f2(11)
Thread:11 f1(1)
Thread:12 f1(2)
Thread:10 f1(3)
Thread:11 f1(4)
Thread:12 f2(12)
Thread:11 f2(13)
Thread:10 f2(14)
Thread:9 g1()
今度はg()メソッドだけがテストのスレッドプール(スレッド8、9)を利用している。データプロバイダを使った2つのメソッド(f1()とf2())はデータプロバイダのスレッドプール(スレッド10、11、12)を共有している。
この新機能で、TestNGを使った並行テストがより簡単になった。大量データを戻すデータプロバイダを使ったテストで実行時間を大幅に短縮できるだろう。
データプロバイダでの並行テストはTestNG 5.10に含まれるがベータバージョンはもうダウンロードできるので、ぜひ試してほしい。