JUnit5試したみた #2 (RepeatedTest)

前回に引き続き、JUnit5について書きます。今回は、RepeatedTestについてです。

RepeatedTest

指定した回数@RepeatedTestを付与したテストメソッドを実行してくれます。具体的に言うと、@RepeatedTestのvalue属性に実行したい回数を指定します。

サンプルコード

実行結果

f:id:b1a9id:20171230113258p:plain

解説

BeforeEachは、各テストの各繰り返し回数ごとに実行される

以下の結果から見出しのことが言えます。

表示名がカスタマイズできる

RepeatedTestでは、先に説明したことに加えて、繰り返し回数ごとに表示名(displayName)をカスタマイズすることができます。デフォルトの表示名は、RepeatedTest.SHORT_DISPLAY_NAMEである、「repetition [現在の実行回数] of [実行すべき回数]」です。
静的なテキストと動的なプレースホルダーから成り立つメッセージを、@RepeatedTestのname属性に指定します。
用意されているプレースホルダーは、次の3つになります。

{displayName} @RepeatedTestメソッドのdisplayName
{currentRepetition} 現在の実行回数
{totalRepetitions} 実行すべき回数

繰り返し回数ごとに表示名を変更しているテストが、customDisplayName()メソッドとcustomDisplayNameLongPattern()メソッドになります。
後者のテストでは、name属性にRepeatedTest.LONG_DISPLAY_NAMEを指定しています。実際に表示されるメッセージは、「Details... :: repetition [現在の実行回数] of [実行すべき回数]」です。

ここで、現在の実行回数や実行すべき回数ってどう取得すればいいの?って疑問がでてくると思います。
RepetitionInfoインターフェースをインジェクトすることで解決できます。
これは、getCurrentRepetition()メソッドとgetTotalRepetitions()メソッドを持ったインターフェースで、@RepeatedTest、@BeforeEach、@AfterEachが付与されたメソッドにのみインジェクトすることができます。
@RepeatedTestが付与されたメソッドが存在しないクラスで、@BeforeEachまたは@AfterEachが付与されたメソッドにRepetitionInfoをインジェクトしようとすると、ParameterResolutionExceptionがスローされます。
customDisplayName()メソッドを見てもらえば、使い方がわかると思います。

次回は、ParameterizedTestについて書きます。

JUnit5試したみた #1

JUnit5が9/10にリリースされました。リリースからちょっと時間が経ってしましましたが、JUnit5について書きたいと思います。

What' new JUnit5?

大きな違いと言えば、3つの異なるサブプロジェクトから構成されていることです。以前のバージョンまでは、1プロジェクトで構成されていました。
つまり、こういうことです。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit VintageJUnit 5 User Guide より)

各プロジェクトの役割について簡単に説明します。

JUnit Platform

JVM上でテストフレームワークを動かすための基盤を提供します。

JUnit Jupiter

プラットフォーム上でJupiterベースのテストを動かすためのテストエンジンを提供します。

JUnit Vintage

プラットフォーム上でJUnit3やJUnit4ベースのテストを動かすためのテストエンジンを提供します。

JUnit5の導入

pom.xmlにこれらを追加してください。なお、JUnit5を動かすためには、Java8以上である必要があります。

それぞれの説明は JUnit 5 User Guide に書いてあります。

pom.xml

一般的なテスト

サンプルコードです。

StandardTest.java

アノテーションの説明

テストを書く上で、よく使うアノテーションについて説明します。

@DisplayName

テストクラスやメソッドにつけることができるアノテーションです。
テストランナーやテストレポートが引数で指定した値を表示してくれます。文字列、空白、絵文字などを使うことができます。

@BeforeAll

JUnit4でいうところの@BeforeClassです。
全ての@Test, @RepeatedTest, @ParameterizedTest, and @TestFactory テスト実行前に1度だけ実行されます。

@BeforeEach

JUnit4でいうところの@Beforeです。
@Test, @RepeatedTest, @ParameterizedTest, and @TestFactory 各テスト実行前に実行されます。

@Disabled

JUnit4でいうところの@Ignoreです。
これをつけたテストクラス及びメソッドは実行されません。

実行結果

IntelliJ IDEAで実行しています。

@DisplayNameの表示

@DisplayNameで指定した値が表示されていることがわかります。今まではコメントとしてどういったテストか書いていたのでありがたいです。
f:id:b1a9id:20171226114300p:plain

結果出力

@BeforeAllがクラス内で1度だけ、@BeforeEachが各テスト前に実行されていることがわかります。

executed before all test just once.
executed before each test.
This is test1.

This is Disabled test.
executed before each test.
This is test3.

基本的なアサーションの紹介

サンプルコードです。
基本的にはJavaDocを読めば理解できると思います。

StandardAssertionTest.java

Assertions#assertAll

第1引数で指定している値は、テスト失敗時にメッセージに含みたい値になります。
DependentAssertions#nameAssertionsの失敗例です。

org.opentest4j.MultipleFailuresError: This is name test. (1 failure)
	expected: <Ryo> but was: <Ryosuke>

Assertions#fail

AssertionFailedErrorを投げて必ずテストを失敗させる。値を返す前に例外を投げる。AssertJのassertThatThrowByを使ってたら使い道なさそう...


Assumption

Assumption#assumeTrueとかの結果がTrueだったら、それ以降に書いた検証を実行します。厳密には、TestAbortedExceptionを投げてテストを中断させています。
AssumptionAssertions#invalidTestでAssumption#assumeFalseの第2引数に渡した「() -> "This is invalid."」は、テストが中断したときにメッセージに含みたい値になります。

org.opentest4j.TestAbortedException: Assumption failed: This is invalid.

実行結果

AssumptionAssertionsクラスで中断されたテストは結果に出力されていないことがわかると思います。中断されたことは、ログに出力されます。
f:id:b1a9id:20171226154151p:plain

今回は、JUnit5の導入的なところ触れてみました。次回は実用的なテストを書こうと思います。
ちなみに使用したサンプルコードはこちらにあります。
github.com

JJUG CCC 2017 FallでAssertJを推してきた

11/18(土)に開催されたJJUG CCC 2017 Fallで1年ぶりに登壇してきました。
タイトルは、「ユニットテストアサーション 流れるようなインターフェースのAssertJを添えて 入門者仕立て」でした。(フレンチのメニューをオマージュしました)
f:id:b1a9id:20171124004247j:plain

50人くらいの部屋だし、11時からだったので半分入ればいいかなと思っていました。でも10分前くらいには既に70人くらい入っていて緊張MAX!!!

何回か練習したから大丈夫と思ってたけどやはり人前に立つと緊張する〜
AssertJ使ったことある人という質問に対して、1割いるかいないかでしたね。素敵なのに案外使われていないことが判明!
自分のレベルの話しでも、AssertJいいなって思ってくださった人がけっこういて非常によかった♪
今回は、大事故スライドなしで挑んでよかったわw(当日の2時まで入ってたけど消した)
ちなみにスライドはこちら。

www.slideshare.net

話して感じたことここまでにして、アンケートで質問等をちょっといただいたのでそれの回答をしようかと思います!

いただいた意見と回答

1.JUnitとの記述の比較がとてもわかりやすかったです。使っている人がまだ少なそうなので、情報を探すのは大変ではなかったでしょうか。そのような点もお話聞かせていただきたいと思いました。

結論から述べると、公式リファレンス読んで、JavaDoc読んで、コード読みました。
まず、AssertJを使おうと思ったきっかけはこの本です!
gihyo.jp

これを見ていた時ちょうど、会社でユニットテストライン80%目指そうぜ計画がはじまりました。
Serviceのテストを書いていて、assertEqualsいっぱいだし、コピペでつまんないってって思っていました。そこでAssertJを書いてみると、書きやすさ、コードの美しさ、エラーメッセージのわかりやすさどれをとっても素敵でした。
AssertJは、1年くらい使ってるのでそれなりの知見はあったのですが、登壇のためにリファレンスを1から読みました。そして実際に手を動かしました。
AssertJの公式リファレンスは、ロードオブザリングとかスターウォーズのキャラクター出てきて案外楽しく読めます!JavaDocは、書き方例が書いてあって理解しやすいです。

2.自分も知らない使い方の紹介もあって良かったです hamcrest matcherとの違いやメソッドチェーンの説明があるともっとわかりやすかったと思いました。

既に使っていらっしゃるんですね。ためになること話せてよかったです。
なお、hamcrest matcherの経験はほぼ皆無(ほぼAssertJしか使ったことない)なのです。
メソッドチェーンの説明とは、それぞれの検証のことですかね?次回に活かします!


以上です。
登壇するとフィードバックがよくても悪くてもとても嬉しいです。
またネタ探して登壇したいと思います!!!

AssertJで流れるようなインターフェースでアサーションを書こう #1

みなさんユニットテスト書いてますか?アサーションライブラリは何を使ってますか?私は、Assert Jが好きで使ってます。

AssertJは、Javaアサーションライブラリで、主にAssertJ CoreとAssertJ SwingとAssertJ DBがあります。
今回は、AssertJ Coreについて書きます。第1回は、概要と導入手順です。
AssertJ Coreは、流れるようなインターフェースでアサーションを書くことができるJavaライブラリで、テストコードを読みやすく改善し、簡単にメンテナンスしやすくすることが主な目的です。
メソッドチェーンで複数の検証を一度に書くことができます。また、JDKの標準タイプのアサーションを提供していて、JUnitTestNGで使うことができます。

バージョン

バージョンは、下の表のようになっています。(2017/10/19時点)3系の大きな特徴は、Project Lambdaを使用した検証ができることです。また、OptionalやDate and Time APIの各クラスの検証もできます。
これらの機能に加えて、2系のすべての機能が利用できます。

Javaバージョン 初期リリース 最新
3系 Java8以上 2015/04/06(3.0.0) 2017/05/21(3.8.0)
2系 Java7以上 2015/03/07(2.0.0) 2017/05/21(2.8.0)
1系 Java6以上 2013/03/26(1.0.0) 2015/01/02(1.7.1)

類似ライブラリ

AssertJ Android

AssertJを拡張したAndroid用のアサーションライブラリです。
square.github.io

Assert Py

AssertJに影響を受けて作られてたPython用のアサーションライブラリです。
github.com

導入手順

依存関係の追加

Spring Boot(>=1.4)を使う場合

その他の場合

  • Gradle

Spring Boot(>=1.4)を使う場合

その他の場合

Spring Bootを使う場合、spring-boot-starter-testには、AssertJが含まれています。しかし、デフォルトで2.6.0が入っているので3.8.0を使う場合は、バージョン指定が必要です。

依存ライブラリがないので、導入がしやすいです。
次回は、実際にどういう風にアサーションが書けるかについてです。

ThymeleafでNumber.javaを継承したクラスをメッセージ式のパラメータとして渡すと千の位で区切ってくれる話

先日、仕事でThymeleafで千の位で区切って表示することをやりました。いわゆる金額表示です。
結論から述べると、以下のようにすると、実現できます。

ちなみにこれはたまたま発見できちゃいました。。。笑
最初は、次のように書いてました。

<p th:text="${#numbers.formatInteger(1234567890, 3, 'COMMA')} + '円'">1,234,567,890円</p>

ある記事を読んでいてメッセージ式にパラメータを渡せることを知りました。
そこでカンマ区切りのことは気にせず、上のように書いてみたら、金額表示になってました。
しかし、なぜ数値をパラメータとして渡すと千の位で区切ってくれる(区切って欲しくないときもあるけど)のか気になったのでソースコード追ってみました。
MessageSourceインターフェースのgetMessageメソッドにブレークポイントを張りました。
MessageFormat.java#subformatが気になりました。

案の定、16行目に止まり、ここでsubformatにDecimalFormat.javaを返していました。
そして、DecimalFormat.javaのsubformatメソッドに処理がうつり、ここで実際に1000の位に区切っていました。それが以下の箇所です。

実際にソースを読んでもらえればわかるのですが、groupingという変数に「,」が格納されています。
DecimalFormatSymbols (Java Platform SE 8 )
ループで回し、パラメタを1個ずつ渡して、1000の位で「,」を入れています。

ちなみに、NumberFormatProvider.javaにこのようなメソッドがあったのでこれをうまく呼ぶ方法を見つけたいなと思いました。

public abstract NumberFormat getCurrencyInstance(Locale locale);

以上です。

Intelli Jのショートカット一覧が日本語訳されました

以前、Intelli Jのショートカットを以下の記事でまとめたのですが、公式で発表されてるのもを日本語訳された会社さんがいらっしゃいました。
uchi-fashion.hatenablog.com

こっちの方が私の拙い日本語訳より参考になると思うのでぜひ!
IntelliJ や PhpStorm などの日本語化

Intelli J ショートカットまとめ

4回にわたってIntelli Jのショートカットをまとめたのですが、みてる自分がめんどくさくなったので1つにまとめました。
Keymapは、Mac OS Xです。異なる方はちょいとキーが変わってくると思います!

Editing
ショートカットキー 説明
^ Space ベーシックなコード補完(いくつかクラスやメソッドや変数の候補をあげる)
^ Shift Space スマートなコード補完(そのメソッドで期待されるタイプの変数の候補をあげる)
Command P パラメータ情報表示
^ J クイックドキュメント表示
Command コードをマウスオーバー 簡単なドキュメント表示
^ N GetterやSetterやConstructorなどのコードを生成
Command O オーバーライドメソッドの表示
Command Option T if...elseやtry...catchなどの雛形コード生成
Command / カーソルがある行のコメントアウト
^ Shift Q コンテキスト情報の表示。puclic class Test extends Hoge { を表示
Command Option L コードフォーマット
^ Shift O import文の整理。使ってないものの削除やソートを行う
Command D カーソルがある行を下に向かってコピペを行う
Command Enter カーソルがある箇所から改行する
Shift Enter カーソルがある行の次の行に空行を追加
Command Shift [ カーソルがある箇所のブロックの始まりからカーソルの箇所まで選択
Command Shift ] カーソルがある箇所からブロックの終わりまで選択
Option → カーソルが単語の終わりに遷移
Option ← カーソルが単語の始まりに遷移
Command W カーソルがある単語を選択
Command Shift U 選択してる単語の大文字小文字切り替え
Command G 開いたモーダルで指定した行数に遷移する
Usage Search
ショートカットキー 説明
Option F7 プロジェクト内でカーソルが当たっているクラス(メソッド)が使われている箇所を表示
Command F7 ファイル内でカーソルが当たっているクラス(メソッド)が使われている箇所を表示
Command Shift F7 ファイル内でカーソルが当たっているクラス(メソッド)が使われている箇所を強調して表示
Command Option F7 プロジェクト内でカーソルが当たっているクラス(メソッド)が使われている箇所を一覧表示
Navigation
ショートカットキー 説明
F12 アクティブウインドウをツールウインドウにする
ESC アクティブウインドウをエディタにする
Shift ESC (直近の)アクティブウインドウを隠す
Command F4 アクティブなタブを閉じる
Command E 最近開いたファイルをポップアップ表示
Command B または Command Click 変数の宣言箇所にカーソルを移動(Command Clickは変数にカーソルが当たってる時)
Command Option B または Command Click 実装箇所にカーソルを移動(Command Clickはメソッドにカーソルが当たってる時))
Command [ コードブロックのはじまりに移動
Command ] コードブロックの終わりに移動
Command F12 ファイル構成(フィールドやメソッド)をポップアップ表示
^ H タイプハイアラーキーを表示
Command Shift H メソッドハイアラーキーを表示
Option ^ H コールハイアラーキーを表示
Search / Replace
ショートカットキー 説明
Shift * 2 どこでも検索
Command F ファイル内検索
Command R 置換
^ Shift F 全ファイルから文字列検索
VCS/Local History
ショートカットキー 説明
^ V バージョン管理システムメニューをポップアップ表示
Refactoring(左ペインで)
ショートカットキー 説明
F5 ファイルのコピー
F6 ファイルの移動
Command Delete セーフデリート
Shift F6 リネーム
Debugging
ショートカットキー 説明
F8 ブレークポイントから一行進める
F7 呼び先のメソッドに入る
F9 次のブレークポイントにとぶ
Shift F8 F7で入ったメソッドから出る
Option F8 ブレークポイントで止まっているときにポップアップウインドウで好きなことを試せる
Command F8 ブレークポイントを解除する
Command Shift F8 ブレークポイントの一覧を表示
ブレークポイントで止まってる時に変数を)Option click 変数の中身が見られる。watchで見られるのと同じ
General
ショートカットキー 説明
Command 1 ~ Command 9 割り当てているツールウインドウを表示
Command ^F フルスクリーンモードにする
Command Shift F12 開いているツールウインドウを全て閉じる
Command , 設定画面開く
Command ; プロジェクトストラクチャーを開く
Others
table>tr>td*2と入力してTabを押す tr * 1、td * 2のテーブルを生成

この中でも1番オススメの機能がこれです!
Option F8:ブレークポイントで止まっているときにポップアップウインドウで好きなことを試せる
f:id:b1a9id:20170707101940p:plain
実際にプロダクトコードで宣言されているものは、vだけです。
変数宣言もできるのでデバッグ能力が格段にあがると思います!
ちなみにAndroid Studioでも使えるらしいのでぜひ試してみてください。