こんにちは、ソリューション開発部の本間です。

この記事は アプレッソ Advent Calendar 2017 の20日目です。アプレッソ Advent Calendar に協力会社も参加しても良いとのことで、書かせていただいています。

アプレッソ Advent Calendar 2017 - Qiita
!(https://www.appresso.com/img/common/logo.jpg "Appresso")(https://www.appresso.com/servista/) をはじめとした「つなぐ」製品を展開する(https://www.appresso.com/)の AdventCalendar です。アプレッソで働くエンジニアたちが、仕事で使っている技...

去る9月に JUnit 5 がリリースされました! 「今すぐ JUnit 5 でテストを書きたい!」そんな前のめりになる開発者っていますよね。わかります、私もそんな一人です。

ですが現場のテストコードは JUnit 4 で書かれており、加えてテスト用の仕組みも JUnit 4 用に作ってあり、JUnit 5 へ移行するにはそれなりの準備が必要です。

この記事ではそんな課題の1つ、JUnit 4 で活用していた @Rule の仕組みを、JUnit 5 向けにリメイクしたことを紹介します。


この記事で扱わないこと:

  • JUnit 5 で assert 系メソッドの使い方や @Test の FQCN が変わったこと
  • テストファーストなど

環境・ライブラリのバージョン:

  • Java 8
  • JUnit 4.12
  • JUnit 5.02

JUnit 4 ではどうしていたか: テストでの共通処理を @Rule で仕組み化する

この記事では、テストコードでの Teardown を題材にします。

  1. まずは仕組み無しのコードを書いて、
  2. JUnit 4 で仕組みを作ります
  3. そして、JUnit 5 へ仕組みを作り直します

という順で説明します。JUnit 5のことが気になるせっかちさんは、後半から読んでくださってOKです。

まずはベタに Teardown を書いてみる

テストコードで外部リソースなどを使う場合は、Teardown フェーズで外部リソースを元の状態に戻すことが基本です。 テストメソッドの中でリソースを元に戻そうとすると、まずは次のようなコードを考えるのではないでしょうか。(“Teardown” とコメントしてある箇所)

ちゃんと動きそうなテストメソッドですが、teardownを確実にするためfinallyが二重になっているあたりが、ちょっと気がかりですね。 次に書くテストメソッドでも同じようにfinallyを書くのは避けたいな… という気持ちが湧いてきます。

レビューする立場に観点を変えてみると、本当に teardown できているよね!? という疑念を持ちそうです。 またテストメソッドに占めるテスト本体部分(Setup〜Exercise〜Verify)の割合が半分くらいであり、テストの主題がぼやけてしまっていることも気がかりです。

@Rule を作る: Teardown ロジックをテストメソッドから追い出す

そこで、Teardown をテストメソッドから追い出して、テストメソッドを読みやすく、かつ確実に Teardown する方法を考えます。 まず先のテストメソッドから Teardown を追い出してみます。

Teardown ロジックを @Rule AutomatedTeardownRule に追い出しました。 Teardown に関する記述が消えただけですが、テストメソッドが読みやすくなりましたね!

また、リソースの作成と AutomatedTeardownRule への登録を一緒にやっているので、Teardown 漏れは無さそうだと安心できます。 追い出された Teardown はテストメソッドの外にあります。

JUnit 4 では TestRule 実装クラスを @Rule にするとテストメソッド実行ごとに TestRule#apply メソッドが呼ばれる仕組みになっているため、上記コードではテストメソッドを実行し終える毎に tearDown が呼ばれます。 JUnit 4 利用時には、このように Teardown 機構とテストメソッドを分けることによって、

  • テストメソッドの可読性向上と、
  • 開発者がテストメソッドに集中できるようにすることと、
  • Teardownの確実性

を獲得していました。

JUnit 5 ではどう実現する?

いよいよ JUnit 5 です。 JUnit 5 では、なんと @Rule の仕組みが廃止されてしまいました! な…なんだってーーー!!

Extension Model

代わりに導入されたのが、Extension Model という仕組みです。(以下 “Extension” と書きます) JUnit を拡張する仕組みとして JUnit 4 では Runner、@Rule, @ClassRule がありましたが、JUnit 5 では Extension に統一されました。 Extension で提供さえている拡張ポイントは10種類以上あり、この記事ではそのうち2つを取り上げます。

Extension を使うようテストコードを直す

JUnit 5 で Extension を使って書き直したテストコードです。

JUnit 4 でのテストコードと似ていますが、変わっている箇所があります:

  • @ExtendWith がクラスに付きました。AutomatedTeardownExtension クラス(後述)によってテストコードを拡張することを示しています。
  • コンストラクタ引数に AutomatedTeardown が増えました。これは AutomatedTeardownExtension による仕業です。

テストメソッド引数の AutomatedTeardown はインタフェースです。(このインタフェースを実装するコードは Extension 側にあります。)

TestRule を Extension Modelで作り直す

AutomatedTeardownRule(JUnit 4) を、Extension Model(JUnit 5) で作り直したコードです。

AutomatedTeardownExtension では、Extension Model の2つの拡張ポイント AfterTestExecutionCallback と ParameterResolver を使用しています。

  • ParameterResolverの2つのメソッドでは、AutomatedTeardownをテストクラスへ渡すことを、
  • AfterTestExecutionCallbackのメソッドでは、テストメソッド終了時にAutomatedTeardown#tearDown を呼ぶことを

それぞれ実現しています。 拡張ポイントを含めた解説をコメント形式で記載したので、参照してください。 以上で、JUnit 4 での カスタム TestRule を、JUnit 5 向けに作り直すことができました! パチパチパチパチ

補足

それ、junit-jupiter-migrationsupport でできるよ!

はい、そのとおりです。 junit-jupiter-migrationsupport は、JUnit 4 の Rule (の幾つか)を JUnit 5 でも利用できるようにするモジュールです。 実は、AutomatedTeardownRule を org.junit.rules.ExternalResource のサブクラスにすることで、JUnit 5 でも @Rule を使い続けることができるのです。 この記事では Extension Model を取り上げたかったため、junit-jupiter-migrationsupport には触れませんでした。 ちなみに junit-jupiter-migrationsupport は Extension Model を使って実現されています。Extension Model を利用するにあたって参考になると思うので、そんな方はソースコードを読むことをオススメします。

Automated Teardown って?

記事の題材として Teardown を仕組み化した “Automated Teardown” を扱いました。(読む人によっては唐突感があったかと思います。) Automated Teardown とは XUnit Test Patterns: Refactoring Test Code という書籍の22章「Fixture Teardown Patterns」で紹介されているテスト戦略の1つです。 機会がありましたら、書いてみたいと思います。

おわりに

Extension Modelすごい!

Extension Model には他にも機能が提供されていて、テストコードを改善するための仕組みを作り易くなっています。 個人的に大きな発見は、JUnit 4 で大きく不満に感じていたことが JUnit 5 で解決されていることに気が付いたことです。 これも機会がありましたら、そのあたりのことを書いてみたいと思います。

おわりにのおわりに

ライブラリのバージョンアップへの追従は、テストコードであってもたいへんです。 とは言え製品側のコードに比べればテストコード向けのライブラリはバージョンアップしやすい現場が多いと感じています。 紹介したように Rule を Extension で作り変えることで、これから書くテストコードでは JUnit 5 を利用できるようになります! 新しい道具を揃えて、使い方を身につけて、より良い成果物を作っていくことは、プログラマの喜びではないでしょうか。 良いテストコードを書いて、良い製品を作りましょう! ではまた。

 

この記事が気に入ったら
いいね!しよう

最新情報をお届けします

Twitter で「株式会社アークシステム」をフォローしよう!

Road to JUnit 5 (はじめてのExtension Model編)https://devlog.arksystems.co.jp/wp-content/uploads/2017/12/junit5-1200x630.pnghttps://devlog.arksystems.co.jp/wp-content/uploads/2017/12/junit5-150x150.pngmanholeソリューション開発部プログラミング開発環境・ツールJava,JUnitこんにちは、ソリューション開発部の本間です。 この記事は アプレッソ Advent Calendar 2017 の20日目です。アプレッソ Advent Calendar に協力会社も参加しても良いとのことで、書かせていただいています。去る9月に JUnit 5 がリリースされました! 「今すぐ JUnit 5 でテストを書きたい!」そんな前のめりになる開発者っていますよね。わかります、私もそんな一人です。 ですが現場のテストコードは JUnit 4 で書かれており、加えてテスト用の仕組みも JUnit 4 用に作ってあり、JUnit 5 へ移行するにはそれなりの準備が必要です。 この記事ではそんな課題の1つ、JUnit 4 で活用していた @Rule の仕組みを、JUnit 5 向けにリメイクしたことを紹介します。この記事で扱わないこと:JUnit 5 で assert 系メソッドの使い方や @Test の FQCN が変わったこと テストファーストなど環境・ライブラリのバージョン:Java 8 JUnit 4.12 JUnit 5.02JUnit 4 ではどうしていたか: テストでの共通処理を @Rule で仕組み化する この記事では、テストコードでの Teardown を題材にします。まずは仕組み無しのコードを書いて、 JUnit 4...ARK Solution Development Division Developers Blog.