Upload
irof-n
View
4.657
Download
4
Embed Size (px)
DESCRIPTION
関西Javaエンジニアの会'13 7月度の発表資料です。
Citation preview
from old JUnitto modern JUnit
関西Javaエンジニアの会'13 7月度@irof
@irof========* ふつうのプログラマ * TDD
* Java, Jenkins
* Groovy, Gradle, Git
関西Javaエンジニアの会, hoge駆動,
大阪Jenkins勉強会……とかの中の人。
タイトルの元ネタ(Java1.4から7へアップグレードするのいい資料なので是非)
JUnitの話をだらだらします
おしながき
JUnitを使うわけ
良いテストコードとは
JUnitの進化
JUnit4を使いこなす
JUnitを使うわけ
テスティングフレームワーク
テストを実行する
テスト結果を検証する
テストのフォーマットを提供する
実行方法、記述方法を統一することで、知っている人なら誰でも読めて実行できるようにするのが目的。
xUnitを使うわけ
みんな使ってるから。
テスト実行時に興味の無いことをやってくれるから。
他のツールと連携してくれるから。
IDE, ビルドツール, CI, カバレッジ, テストレポート, etc...
TestNGでないわけ
とくにない。
おしながき
JUnitを使うわけ
良いテストコードとは
JUnitの進化
JUnit4を使いこなす
良いテストコードとは
F.I.R.S.T.
Fast - 高速
Independent - 独立
Repeatable - 再現
Self-Validating - 自己検証
Timely - 適時
A-TRIP
Automatic - 自動
Thorough - 徹底
Repeatable - 再現
Independent - 独立
Professional - 専門的
以上は借りてきた言葉。
良いテストコードとは
失敗の扱いがうまい
読みやすい
失敗の扱いがうまい
失敗すること
すぐ失敗すること
何故失敗したかわかること
どうするべきかわかること
失敗時の振る舞いで良し悪しが決まる
テストの価値は
失敗にある
詳しくはSlideShareで
読みやすい
テストコードはプロダクトコードよりも可読性が求められる。
何故か?
テストのテストは困難。
テストのバグはレビューで潰す?
可読性が高いとバグが減る
“極限まで可読性の高いコードにバグが混入する可能性は限りなく低い”
ってブログに書いてた。私の。
可読性のための構造化
たとえば4フェーズテスト(xUTP)を使う
Four-Phase Test
@Test public void hoge() { Hoge sut = new Hoge(); String actual = sut.hoge(); assertThat(actual, is("fuga")); }
フェーズの間を1行空けるとかsetup
exercise
verify
構造がわかると読みやすくなる
おしながき
JUnitを使うわけ
良いテストコードとは
JUnitの進化
JUnit4を使いこなす
JUnitの進化
JUnit 3
public class JUnit3Test extends TestCase { public void testHoge() { assertEquals(2, 1); }}
JUnit 4
public class JUnit4Test { @Test public void hoge() { assertThat(1, is(2)); }}
TestCaseの継承が不要。
メソッド名のtest始まり制約が不要。
メソッドに@Testを付ける。
assertThatが標準(個人の趣味)
JUnit3 to JUnit4
何が嬉しい?
TestCaseの継承が不要。Javaの継承は1クラスのみ。
いざと言う時のカードが残せる。
何が嬉しい?
メソッド名のtest始まり制約が不要。
testのtypoが無くなる。
日本語テストメソッド名の違和感が軽減される。
何が嬉しい?
assertThatが標準。Matcherが使える。
あと引数の順番(ブログ参照)
※補足※
assertThatはJUnit4.4でAssertクラスに追加されたが、hamcrestを直接使用すればJUnit3でも使える。
所詮AssertionErrorを投げるだけだし。
JUnit4.4以降の主な機能
4.4 - assertThat, Theories
4.7 - Rule(MethodRule)
4.8 - Categories
4.9 - TestRule
4.10 - RuleChain
4.11 - FixMethodOrder
※個人の趣味で抜粋
おしながき
JUnitを使うわけ
良いテストコードとは
JUnitの進化
JUnit4を使いこなす
JUnit4を使いこなす
JUnit4の三本柱
MatcherRuleRunner
Matcher
ひとまとまりの検証に名前をつけてひとまとめにする。
テストコード自体の可読性の向上
失敗時メッセージの可読性の向上
describeTo/describeMismatchで失敗時のメッセージを編集可能。
describeMismatchはhamcrest1.2以降(最新は1.3)JUnit実践入門は1.1のため未掲載
Matcherの使い方
assertThat(today, is(dateOf(2013, 2, 3)));
java.lang.AssertionError: Expected: is "2013/02/03" but: "2013/07/31" at org.hamcrest.MatcherAssert.assertThat(MatcherAssert at org.junit.Assert.assertThat(Assert.java:865) at org.junit.Assert.assertThat(Assert.java:832) at JUnit4Test.hoge(JUnit4Test.java:24) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
describeMismatchで編集可
describeToで編集可
メッセージがわかりやすい!
ステキ!!
Rule
とりあえずExpectedExceptionは覚える。
他はおいおいでも……
@Ruleと@ClassRuleがある。
基本は@Ruleを使う。
Ruleの活用例
例外を検証するRuleとか(後述)
Logを検証するRuleとか(作れる)
TestWatcherを拡張すると捗る。
starting/finished
succeeded/failed/skipped
例外のテスト
old Exception Test
@Test public void hoge() { try { sut.hoge(); fail(); } catch(NullPointerException e) { assertEquals("ぬるぽ", e.getMessage()); } }
modern Exception Test
@Test(expected = NullpointerException.class)public void hoge() { sut.hoge();}
例外の型だけで良いならこれでおk
modern Exception Test
@Rulepublic ExpectedException thrown = ExpectedException.none();
@Testpublic void hoge() { thrown.expect(NullPointerException.class); thrown.expectMessage("ぬるぽ"); sut.hoge();}
modern Exception Test
例外が発生しなかった場合の fail を書かなくて良い(忘れない)。
try-catchのような構造がテストコード内に出現しない。
(例外の検証にMatcherを使える)
Ruleを使えば継承無しで横断的なルールを適用できる!
しかも組み合わせ放題!(継承では難しい)
ステキ!!
Runner
JUnitの実行方法を制御する。
標準機能で以下が提供。
Enclosed
Parameterized
Theories
Suite
Categories
Runnerの活用例
Arquillian
WebコンテナでJUnitのテストを実行する。
SpringTest
ApplicationContextの初期化をしてくれたりする。
Runnerをいじる
「実行方法の制御」
その気になれば何でもできる。
TestNGのテストも実行できる。
ネタだけど
続きはWebで
JavaAdventCalendar2011で似たこと書いてます。
まとめ
まとめ
JUnitも進化してます。
昔の常識、今は?
最新を追うと色々見えて楽しい。
one more thing...
Groovy x JUnit
Groovy x JUnit
JUnitのテストをGroovyで書く。
Spockを使う。
JUnitを拡張したフレームワーク
@RunWith(Sputnik.class)
JUnitとして実行できる!
Spockの例
class HelloSpock extends spock.lang.Specification { def "length of Spock's and his friends' names"() { expect: name.size() == length
where: name | length "Spock" | 5 "Kirk" | 4 "Scotty" | 6 }}
詳しくは別の機会に。