Chapter 19.
xUnit Basic
 Patterns
●   Test Definition
    ●   Test Method
        –   Four-Phase Test
    ●   Assertion Method
        –   Assertion Message...
Test Method
How It Works(1)
●   テストコードってどこに書くの?
    ●   ひとつひとつのテスト毎にメソッド (Test Method) にし
        てクラスに配置しましょう
●   How It Works
    ● ...
How It Works(2)
●   Test Method には標準 Template がある
    ●   Simple Success Test
        –   正常系のテスト。 Fixture setup から result...
Why We Do This
●   手続き型言語の場合
    ●   Test Method をファイルやモジュールに書く
●   オブジェクト指向言語の場合
    ●   Test Method を Testcase Class(373...
Implementation Notes
●   どう仕組みを実装する?
    ●   Static method として実装し呼び出しを列挙する
        –   テスト結果を集めたりする共通化がやりにくい
    ●   Test ...
Simple Success Test
●   ソフトウェアには正常系 “happy path” があ
    る。Simple Success Test はそれを書く
    ●   SUT をインスタンス化して叩き、結果を assert
 ...
Simple Success Test のダメな例

public void testFlightMileage_asKm() throws Exception {
  //set up fixture
  Flight newFlight =...
Simple Success Test の良い例

public void testFlightMileage_asKm() throws Exception {
  //set up fixture
  Flight newFlight = ...
Expected Exception Test (1)
●   多くの不具合は正常系以外のパスに潜む。特に例
    外系のシナリオ。それは、
    ●   Untested Requirements (268) や、
    ●   Unt...
Expected Exception Test (2)
●   想定される (expected) 例外には、テストを書いた
    ほうがよい
●   再現が難しいが、出るかもしれない (might raise)
    例外には、テストを書か...
Expected Exception Test (3)
●   例外をテストするときの仕組み
    ●   JUnit 3.x
        –   ExpectedException クラスを継承させる (?)
             ...
Expected Exception Test のダメな例

public void testSetMileage_invalidInput() throws Exception {
  //set up fixture
  Flight ne...
Expected Exception Test の良い例

public void testSetMileage_invalidInput()throws Exception {
  //set up fixture
  Flight newF...
Expected Exception Test の特殊例?
public void testSetMileage_invalidInput2() throws Exception {
  //set up fixture
  Flight ne...
Method Attribute を使った EET
[Test]
[ExpectedException(typeof( InvalidArgumentException),
                       "Flight mile...
Block を使った EET
Smalltalk:

testSetMileageWithInvalidInput
 self
  should: [Flight new mileage: -1122]
  raise: RuntimeErro...
Rspec でやってみる
describe Flight do
 before do
  @flight = Flight.new
 end

 it "Should have raised error" do
   lambda {
    ...
Constructor Test
●   Fixture Setup phase で作成されたオブジェクトが
    正しく作成されているかを各 Test Method で調べ
    ていると Test Code Duplication (2...
Dependency Initialization Test
●   Constructor Test の亜種
●   置き換え可能な依存があるオブジェクトがある場
    合、本番環境では本物の依存オブジェクトが参照さ
    れることをテス...
Constructor Test のダメな例
public void testFlightMileage_asKm2() throws Exception {
  //set up fixture
  //exercise constructo...
Constructor Test の良い例1 正常系
public void testFlightConstructor_OK() throws Exception {
  //set up fixture
  //exercise SUT
 ...
Constructor Test の良い例2 異常系
public void testFlightConstructor_badInput() {
  //set up fixture
  BigDecimal invalidFlightNum...
Constructor Test があると他のテストの
        ピントがはっきりする
 public void testFlightMileage_asKm() throws Exception {
   //set up fixtur...
Four-Phase Test
●   Test Definition
    ●   Test Method
        –   Four-Phase Test
    ●   Assertion Method
        –   Assertion Message...
Four-Phase Test
●   良いテストには4つの Phase がある
    ●   Setup
    ●   Exercise
    ●   Verify
    ●   Teardown
●   ワンパターン = テストの読...
Four-Phase Test
●   どう setup/teardown する?
    ●   Testcase Class per Class または Testcase Class
        per Feature の場合
    ...
例: Four-Phase Test (In-line)

public void testGetFlightsByOriginAirport_NoFlights_inline() throws Exception {
  //Fixture ...
例: 4PT (Implicit Setup/Teardown)
NonTxFlightMngtFacade facade = new NonTxFlightMngtFacade();
private BigDecimal airportId;...
Assertion Method
●   Test Definition
    ●   Test Method
        –   Four-Phase Test
    ●   Assertion Method
        –   Assertion Message...
Assertion Method
●   どうやってテストに自己チェックさせるか
    ●   ユーティリティメソッドを呼ぶことで望んだ結果になった
        かどうかの評価をすればいい
●   Fully Automated Test...
Why We Do This
●   期待する結果を Conditional Test Logic(200)で
    表現すると…
    ●   饒舌に過ぎ、読むのも理解するのも難しい
    ●   Test Code Duplicati...
まずはひどい例から
if (x.equals(y)) {
    throw new AssertionFailedError(
        "expected: <" + x.toString() +
        "> but fou...
JUnit はこうリファクタリングした
/**
 * Asserts that two objects are equal. If they are not,
 * an AssertionFailedError is thrown with ...
Implementation Notes
●   全ての xUnit ファミリーは Assetion Method を備
    えているが、考えるべきことはある
    ●   Assertion Method をどうやって呼ぶか
    ●...
Calling Built-in Assertion Methods
●   Test Method(348) からテストフレームワーク組み
    込みで提供されている Assertion Method を呼ぶ
    には…
    ●  ...
Assertion Messages
●   テスト失敗時の出力に含めるメッセージ
    ●   どのテストが失敗したかをわかりやすくする
        –   Assertion Roulette 参照
    ●   省略可能な引数とし...
Choosing the Right Assertion
●   Assertion Method には二つのゴールがある
    ●   期待しない結果のときにはテストを失敗させること
    ●   SUT がどう振る舞うかのドキュメントに...
Equality Assertion
●   結果が期待値と等価かどうかを調べる
    ●   もっとも使われる Assertion Method
●   引数の順番は規約としては expected, actual の
    順番
    ...
Equality Assertion いろいろ
assertEquals( expected, actual ); // since JUnit3.x

assertThat( actual, is(expected) ); // since ...
Fuzzy Equality Assertion
●   結果と期待値との完全な一致が難しい場合
    ●   浮動小数点をあつかうとき
    ●   期待値と完全一致させるには結果に本質的でない不要
        なゴミが多いとき (X...
Stated Outcome Assertion
●   期待値を渡す必要がないとき
●   Conditional Test Logic を避けるためのガード節
    としても使える



assertNotNull(a );

asser...
Expected Exception Assertion
●   ブロックやクロージャを備えている言語は発生する
    であろう例外をパラメータとして渡す Assertion
    Method が使える

self
  should: [...
Single-Outcome Assertion
●   常に同じ振る舞いをする Assertion Method
    ●   例えば fail メソッド
●   使われる状況
    ●   まだ完成していないテスト Unfinished...
Single-Outcome Assertion の例

public void testSetMileage_invalidInput()throws Exception {
  //set up fixture
  Flight newFl...
Assertion Message
●   Test Definition
    ●   Test Method
        –   Four-Phase Test
    ●   Assertion Method
        –   Assertion Message...
Assertion Message
●   どの Assertion Method が落ちたか知りたい
    ●   Assertion Method 毎にメッセージ引数を渡す
●   テスト失敗時の出力に含めるメッセージ
    ●   ど...
When to Use It
●   二つの学派(School)がある
    ●   テスト駆動派 (Test drivers) と、その他派
●   テスト駆動派
    ●   “single assertion per Test Met...
Implementation Notes
●   Assertion Message に何を書くべきか
    ●   Assertion-Identifying Message
    ●   Expectation-Describing M...
Assertion-Identifying Message
●   同種の Assertion Method が複数ある場合にどれ
    が失敗したか分かりにくい
    ●   Assertion Method 毎に違う文字列を渡して識別す...
Expectation-Describing Message
●   テストが失敗した時に「実際何が起こったか」はわ
    かる。だが「何が起こるべきだったか」はわからな
    い。
    ●   テストコード内にコメントを書く手もある
...
Argument-Describing Message
●   いくつかの Assertion Method は失敗時の出力が
    不親切
    ●   特に Stated Outcome Assertion
        –   as...
Argument-Describing Messageの例

assertTrue( "Expected a > b but a was '" + a.toString() +
         "' and b was '" + b.toSt...
ご清聴
 ありがとう
ございました
Upcoming SlideShare
Loading in...5
×

xUnit Test Patterns - Chapter19

8,741

Published on

handout for xUnit Test Patterns Reading Group Japan

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
8,741
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
29
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Transcript of "xUnit Test Patterns - Chapter19"

  1. 1. Chapter 19. xUnit Basic Patterns
  2. 2. ● Test Definition ● Test Method – Four-Phase Test ● Assertion Method – Assertion Message ● Testcase Class ● Test Execution ● Test Runner ● Testcase Object ● Test Suite Object ● Test Discovery ● Test Enumeration ● Test Selection
  3. 3. Test Method
  4. 4. How It Works(1) ● テストコードってどこに書くの? ● ひとつひとつのテスト毎にメソッド (Test Method) にし てクラスに配置しましょう ● How It Works ● 各テストをメソッド/手続き/関数のかたちで Four- Phase(358) の実装を行い、Fully Automated Test と する。 ● 大事なのは、 assertion を書いて自己テストコード (Self-Checking Test:26) とすること
  5. 5. How It Works(2) ● Test Method には標準 Template がある ● Simple Success Test – 正常系のテスト。 Fixture setup から result verification ま で一本道 ● Expected Exception Test – 例外系のテスト ● Constructor Test – オブジェクトを作成し属性をテストするだけのテスト
  6. 6. Why We Do This ● 手続き型言語の場合 ● Test Method をファイルやモジュールに書く ● オブジェクト指向言語の場合 ● Test Method を Testcase Class(373) の中に書 き、Test Discovery(393) や Test Enumeration(399) を使って Test Method を Testcase Object(382) とし てインスタンス化する ● 標準 template に従うことでテストを読みやすくシンプ ルにし、 SUT の動くドキュメントとすることができる
  7. 7. Implementation Notes ● どう仕組みを実装する? ● Static method として実装し呼び出しを列挙する – テスト結果を集めたりする共通化がやりにくい ● Test Method 一つ一つに対応する Test Suite Object(387)をつくる – Test Discovery や Test Enumaration でインスタンス化する 場合に便利 ● 静的型付け言語の場合はメソッドに “throws Exception” などを書かなければならない – コンパイラに対して「この例外は Test Runner が処理するよ」 という意思表示になる ● 殆どの Test Method は3パターンに分類できる
  8. 8. Simple Success Test ● ソフトウェアには正常系 “happy path” があ る。Simple Success Test はそれを書く ● SUT をインスタンス化して叩き、結果を assert – 言い換えると、 Four-Phase に則ったテストを書く ● 例外はキャッチせず、 Test Automation Framework ま で貫通させる – テストの中で例外を扱うと Obscure Test や誤解のもと – Tests as Documentation の原則を思い出そう – Try-catch を書かない利点は他にもあって、 Test Automation Framework が例外発生行を特定しやすくなる こと
  9. 9. Simple Success Test のダメな例 public void testFlightMileage_asKm() throws Exception { //set up fixture Flight newFlight = new Flight(validFlightNumber); try { //exercise SUT newFlight.setMileage(1122);     //verify results int actualKilometres = newFlight.getMileageAsKm(); int expectedKilometres = 1810; //verify results assertEquals( expectedKilometres, actualKilometres); } catch (InvalidArgumentException e) { fail(e.getMessage()); } catch (ArrayStoreException e) { fail(e.getMessage()); } } 不要な try/catch
  10. 10. Simple Success Test の良い例 public void testFlightMileage_asKm() throws Exception { //set up fixture Flight newFlight = new Flight(validFlightNumber); newFlight.setMileage(1122); //exercise mileage translator int actualKilometres = newFlight.getMileageAsKm();     //verify results int expectedKilometres = 1810; assertEquals( expectedKilometres, actualKilometres); } xUnit は unexpected exception を 失敗として扱えるので、 throws Exception しておけばよい
  11. 11. Expected Exception Test (1) ● 多くの不具合は正常系以外のパスに潜む。特に例 外系のシナリオ。それは、 ● Untested Requirements (268) や、 ● Untested Code (268) であったりするため ● Expected Exception Test はわざと SUT が例外 を出すようなテストを書き、きちんと例外が出ること を調べる ● 例外の中身も調べたいときは Equality Assertion で調 べる ● 例外が出なかったときは fail メソッドなどでテストを失 敗させる
  12. 12. Expected Exception Test (2) ● 想定される (expected) 例外には、テストを書いた ほうがよい ● 再現が難しいが、出るかもしれない (might raise) 例外には、テストを書かなくてよい ● (★ ネットワーク障害とか、 Disk full とか) ● そういう例外は Simple Success Test の失敗として現 れるため ● もしそういう例外もテストしたいなら、 Test Stub から例 外を発生させてテストする
  13. 13. Expected Exception Test (3) ● 例外をテストするときの仕組み ● JUnit 3.x – ExpectedException クラスを継承させる (?) ● 小さいテストクラスが沢山できるし、あまり旨味は無い ● JUnit 4.x, NUnit – Test Method の annotation/attribute に書く ● Block のある言語 (Smalltalk, Ruby, …) – Block で例外が発生するか調べるテストを書ける
  14. 14. Expected Exception Test のダメな例 public void testSetMileage_invalidInput() throws Exception { //set up fixture Flight newFlight = new Flight(validFlightNumber); //exercise SUT     newFlight.setMileage(-1122); //invalid //how do we verify an exception was thrown? } 想定された例外なのにテストが失敗してしまう
  15. 15. Expected Exception Test の良い例 public void testSetMileage_invalidInput()throws Exception { //set up fixture Flight newFlight = new Flight(validFlightNumber); try {     //exercise SUT newFlight.setMileage(-1122); fail("Should have thrown InvalidInputException"); } catch(InvalidArgumentException e) { //verify results assertEquals( "Flight mileage must be positive", e.getMessage()); } } 想定される例外を catch する 例外が出なかった場合は fail させる
  16. 16. Expected Exception Test の特殊例? public void testSetMileage_invalidInput2() throws Exception { //set up fixture Flight newFlight = new Flight(validFlightNumber); try { //exercise SUT newFlight.setMileage(-1122);     //cannot fail() here if SUT throws same kind of exception } catch(AssertionFailedError e) { //verify results assertEquals( "Flight mileage must be positive", e.getMessage()); return; } fail("Should have thrown InvalidInputException"); } Fail メソッドが投げる例外と同じ例外を SUT が投げる場合にはこう書くしかない !?
  17. 17. Method Attribute を使った EET [Test] [ExpectedException(typeof( InvalidArgumentException), "Flight mileage must be > zero")] public void testSetMileage_invalidInput_AttributeWithMessage() { //set up fixture Flight newFlight = new Flight(validFlightNumber);     //exercise SUT newFlight.setMileage(-1122); }
  18. 18. Block を使った EET Smalltalk: testSetMileageWithInvalidInput self should: [Flight new mileage: -1122] raise: RuntimeError new 'Should have raised error' Ruby: def testSetMileage_invalidInput flight = Flight.new() assert_raises( RuntimeError, "Should have raised error") do flight.setMileage(-1122) end end
  19. 19. Rspec でやってみる describe Flight do before do @flight = Flight.new end it "Should have raised error" do lambda { flight.setMileage(-1122) }.should_raise(RuntimeError) end end
  20. 20. Constructor Test ● Fixture Setup phase で作成されたオブジェクトが 正しく作成されているかを各 Test Method で調べ ていると Test Code Duplication (213) がひどく なる ● オブジェクト作成のテストだけ別の Test Method にす ることで他のテストをシンプルにすることができる ● Defect Localication にもなる – 各属性の Test Method を分けるとさらに Defect Localization ● Constructor Test は Simple Success Test の形をと る場合もあるし、 Expected Exception Test の形をと る場合もある
  21. 21. Dependency Initialization Test ● Constructor Test の亜種 ● 置き換え可能な依存があるオブジェクトがある場 合、本番環境では本物の依存オブジェクトが参照さ れることをテストする ● ふつうの Constructor Test と分けて管理した方 がよい
  22. 22. Constructor Test のダメな例 public void testFlightMileage_asKm2() throws Exception { //set up fixture //exercise constructor Flight newFlight = new Flight(validFlightNumber); //verify constructed object assertEquals(validFlightNumber, newFlight.number); assertEquals("", newFlight.airlineCode); assertNull(newFlight.airline); //set up mileage     newFlight.setMileage(1122); //exercise mileage translator int actualKilometres = newFlight.getMileageAsKm(); //verify results int expectedKilometres = 1810; assertEquals( expectedKilometres, actualKilometres); //now try it with a canceled flight newFlight.cancel(); try { newFlight.getMileageAsKm(); fail("Expected exception"); } catch (InvalidRequestException e) { assertEquals( "Cannot get cancelled flight mileage", e.getMessage()); } } いろいろやりすぎでピントがあっていない Eager Test
  23. 23. Constructor Test の良い例1 正常系 public void testFlightConstructor_OK() throws Exception { //set up fixture //exercise SUT Flight newFlight = new Flight(validFlightNumber); //verify results assertEquals(    validFlightNumber, newFlight.number ); assertEquals( "", newFlight.airlineCode ); assertNull( newFlight.airline ); }
  24. 24. Constructor Test の良い例2 異常系 public void testFlightConstructor_badInput() { //set up fixture BigDecimal invalidFlightNumber = new BigDecimal(-1023); //exercise SUT try { Flight newFlight = new Flight(invalidFlightNumber);     fail("Didn't catch negative flight number!"); } catch (InvalidArgumentException e) { //verify results assertEquals( "Flight numbers must be positive", e.getMessage()); } }
  25. 25. Constructor Test があると他のテストの ピントがはっきりする public void testFlightMileage_asKm() throws Exception { //set up fixture Flight newFlight = new Flight(validFlightNumber); newFlight.setMileage(1122);     //exercise mileage translator int actualKilometres = newFlight.getMileageAsKm(); //verify results int expectedKilometres = 1810; assertEquals( expectedKilometres, actualKilometres); } インスタンス化直後の assertion は不要
  26. 26. Four-Phase Test
  27. 27. ● Test Definition ● Test Method – Four-Phase Test ● Assertion Method – Assertion Message ● Testcase Class ● Test Execution ● Test Runner ● Testcase Object ● Test Suite Object ● Test Discovery ● Test Enumeration ● Test Selection
  28. 28. Four-Phase Test ● 良いテストには4つの Phase がある ● Setup ● Exercise ● Verify ● Teardown ● ワンパターン = テストの読みやすさ = Tests as Documentation ● Test Method の中身はテスト内容に集中すべし
  29. 29. Four-Phase Test ● どう setup/teardown する? ● Testcase Class per Class または Testcase Class per Feature の場合 – In-line Setup – Garbase-Collected Teardown または In-line Teardown ● Testcase per Fixture の場合 – Implicit Setup ● 例えば setUp メソッド – Implicit Teardown ● 例えば tearDown メソッド
  30. 30. 例: Four-Phase Test (In-line) public void testGetFlightsByOriginAirport_NoFlights_inline() throws Exception { //Fixture setup NonTxFlightMngtFacade facade =new NonTxFlightMngtFacade(); BigDecimal airportId = facade.createTestAirport("1OF"); try { //Exercise system List flightsAtDestination1 = facade.getFlightsByOriginAirport(airportId); //Verify outcome assertEquals( 0, flightsAtDestination1.size() ); } finally { //Fixture teardown facade.removeAirport(airportId ); } }
  31. 31. 例: 4PT (Implicit Setup/Teardown) NonTxFlightMngtFacade facade = new NonTxFlightMngtFacade(); private BigDecimal airportId; protected void setUp() throws Exception { //Fixture setup super.setUp(); airportId = facade.createTestAirport("1OF"); } public void testGetFlightsByOriginAirport_NoFlights_implicit() throws Exception { //Exercise SUT List flightsAtDestination1 = facade.getFlightsByOriginAirport(airportId); //Verify outcome assertEquals( 0, flightsAtDestination1.size() ); } protected void tearDown() throws Exception { //Fixture teardown facade.removeAirport(airportId); super.tearDown(); }
  32. 32. Assertion Method
  33. 33. ● Test Definition ● Test Method – Four-Phase Test ● Assertion Method – Assertion Message ● Testcase Class ● Test Execution ● Test Runner ● Testcase Object ● Test Suite Object ● Test Discovery ● Test Enumeration ● Test Selection
  34. 34. Assertion Method ● どうやってテストに自己チェックさせるか ● ユーティリティメソッドを呼ぶことで望んだ結果になった かどうかの評価をすればいい ● Fully Automated Tests(26)の肝は、テストをSelf- Checking Tests(26)にすること ● そのためには期待する結果を表現し、自動でチェックす ることが必要 ● Assertion Method は期待する結果を表現し、 ● コンピュータにとっては実行可能に ● 人間には Tests as Documentation(23) になる。
  35. 35. Why We Do This ● 期待する結果を Conditional Test Logic(200)で 表現すると… ● 饒舌に過ぎ、読むのも理解するのも難しい ● Test Code Duplication(213)が発生しやすい ● Buggy Test(260)も発生しやすい ● Assetion Method はこの問題を… ● 再利用性の高い Test Utility Methods(599)に複雑さ を移すことにより解決する ● そのメソッドの正しさは Test Utility Tests(599)でテス トすることも可能
  36. 36. まずはひどい例から if (x.equals(y)) { throw new AssertionFailedError( "expected: <" + x.toString() + "> but found: <" + y.toString() + ">"); } else { // Okay, continue // ... } // 上の例では NPE が発生するのでガード節を入れてみると…     if (x == null) { //cannot do null.equals(null) if (y == null ) { //they are both null so equal return; } else { throw new AssertionFailedError( "expected null but found: <" + y.toString() +">"); } } else if (!x.equals(y)) { //comparable but not equal! throw new AssertionFailedError( "expected: <" + x.toString() + "> but found: <" + y.toString() + ">"); } //equal
  37. 37. JUnit はこうリファクタリングした /** * Asserts that two objects are equal. If they are not, * an AssertionFailedError is thrown with the given message. */ static public void assertEquals(String message, Object expected, Object actual) { if (expected == null &&actual == null) return;     if (expected != null && expected.equals(actual)) return; failNotEquals(message, expected, actual); } --------------------------------- assertEquals( x, y ); // 呼び出し側はこれだけ!!
  38. 38. Implementation Notes ● 全ての xUnit ファミリーは Assetion Method を備 えているが、考えるべきことはある ● Assertion Method をどうやって呼ぶか ● 最適な Assertion Method をどう選ぶか ● Assertion Message(370) に何を書くか
  39. 39. Calling Built-in Assertion Methods ● Test Method(348) からテストフレームワーク組み 込みで提供されている Assertion Method を呼ぶ には… ● フレームワークが提供する Testcase Superclass(638) を継承する (JUnit タイプ) ● グローバルクラス/モジュールを完全修飾名で呼び出す (NUnit タイプ) ● Mixin (Test::Unit タイプ) ● マクロ (CppUnit タイプ)
  40. 40. Assertion Messages ● テスト失敗時の出力に含めるメッセージ ● どのテストが失敗したかをわかりやすくする – Assertion Roulette 参照 ● 省略可能な引数として Assertion Method に渡すかた ちが多い ● テスト失敗時に「なぜ失敗したか」の情報が多けれ ばデバッグは容易になる ● 正しい Assertion Method を選ぶことはエラー時のメッ セージ出力を適切にする意味でも重要 ● 問題なのは、 Assertion Message の引数の順番 が xUnit 毎にブレていること
  41. 41. Choosing the Right Assertion ● Assertion Method には二つのゴールがある ● 期待しない結果のときにはテストを失敗させること ● SUT がどう振る舞うかのドキュメントになること ● これらのゴールを満たすため、最適な Assertion Method を選ぶことが重要になる ● Assertion Method には以下のカテゴリがある ● Single-Outcome Assertions ● Stated Outcome Assertions ● Expected Exception Assertions ● Equality Assertions ● Fuzzy Equality Assertions
  42. 42. Equality Assertion ● 結果が期待値と等価かどうかを調べる ● もっとも使われる Assertion Method ● 引数の順番は規約としては expected, actual の 順番 ● 順番は失敗時のメッセージに関係するので重要 ● ★この順番でない xUnit もある。(NUnit とか) ● ★自分の使う Equality Assertion の順を覚えよう ● 内部では等価性を調べるメソッドが呼ばれる ● Java では equals とか ● SUT ごと調べたい場合は Test-Specific Subclass
  43. 43. Equality Assertion いろいろ assertEquals( expected, actual ); // since JUnit3.x assertThat( actual, is(expected) ); // since JUnit 4.4 Assert.AreEqual( actual, expected ); // NUnit is( actual, expected ); // Test::Simple (Perl) equals( actual,     expected ); // QUnit actual.should == expected // Rspec
  44. 44. Fuzzy Equality Assertion ● 結果と期待値との完全な一致が難しい場合 ● 浮動小数点をあつかうとき ● 期待値と完全一致させるには結果に本質的でない不要 なゴミが多いとき (XML の空白ノードとか) assertEquals( 3.1415, diameter/2/radius, 0.001); assertEquals( expectedXml, actualXml, elementsToCompare );
  45. 45. Stated Outcome Assertion ● 期待値を渡す必要がないとき ● Conditional Test Logic を避けるためのガード節 としても使える assertNotNull(a ); assertTrue(b > c ); assertNonZero(b );
  46. 46. Expected Exception Assertion ● ブロックやクロージャを備えている言語は発生する であろう例外をパラメータとして渡す Assertion Method が使える self should: [Flight new mileage: -1122] raise: RuntimeError new 'Should have raised error' assert_raises( RuntimeError, "Should have raised error") { flight.setMileage(-1122) } assert_raises( RuntimeError, "Should have raised error")do flight.setMileage(-1122) end
  47. 47. Single-Outcome Assertion ● 常に同じ振る舞いをする Assertion Method ● 例えば fail メソッド ● 使われる状況 ● まだ完成していないテスト Unfinished Test Assertion を示す ● Expected Exception Test の中の try/catch ブロックで使う fail( "Expected an exception" ); unfinishedTest();
  48. 48. Single-Outcome Assertion の例 public void testSetMileage_invalidInput()throws Exception { //set up fixture Flight newFlight = new Flight(validFlightNumber); try {     //exercise SUT newFlight.setMileage(-1122); fail("Should have thrown InvalidInputException"); } catch(InvalidArgumentException e) { //verify results assertEquals( "Flight mileage must be positive", e.getMessage()); } } 想定される例外を catch する 例外が出なかった場合は fail させる
  49. 49. Assertion Message
  50. 50. ● Test Definition ● Test Method – Four-Phase Test ● Assertion Method – Assertion Message ● Testcase Class ● Test Execution ● Test Runner ● Testcase Object ● Test Suite Object ● Test Discovery ● Test Enumeration ● Test Selection
  51. 51. Assertion Message ● どの Assertion Method が落ちたか知りたい ● Assertion Method 毎にメッセージ引数を渡す ● テスト失敗時の出力に含めるメッセージ ● どのテストが失敗したかをわかりやすくする – Assertion Roulette 参照 ● 省略可能な引数として Assertion Method に渡すかた ちが多い
  52. 52. When to Use It ● 二つの学派(School)がある ● テスト駆動派 (Test drivers) と、その他派 ● テスト駆動派 ● “single assertion per Test Method” ● Test Method に Assertion Method がひとつしかな いので、どの Assertion Method が落ちたかは自明。 故に Assertion Message は不要。 ● その他派 ● ひとつの Test Method に複数 Assertion Method が あるので、 Assertion Message を使いたくなる
  53. 53. Implementation Notes ● Assertion Message に何を書くべきか ● Assertion-Identifying Message ● Expectation-Describing Message ● Argument-Describing Message
  54. 54. Assertion-Identifying Message ● 同種の Assertion Method が複数ある場合にどれ が失敗したか分かりにくい ● Assertion Method 毎に違う文字列を渡して識別する ● 識別に使う文字列の例 ● Assertion Method に使う変数名 – 名前に悩む必要がないので便利かも ● 単なる連番 – テストコードを読まないと結局どこが失敗したかわからなかっ たりする
  55. 55. Expectation-Describing Message ● テストが失敗した時に「実際何が起こったか」はわ かる。だが「何が起こるべきだったか」はわからな い。 ● テストコード内にコメントを書く手もある ● もっと良いのは Assertion Message に期待値の 説明を書くこと ● Equality Assertion の場合は自動でやってくれるので 必要無し ● Stated Outcome Assertion の場合は入れなければ わからない
  56. 56. Argument-Describing Message ● いくつかの Assertion Method は失敗時の出力が 不親切 ● 特に Stated Outcome Assertion – assertTrue(式) とか – 失敗したのはわかるが、どんな式が失敗したのかわからない – 式を Assertion Message に含めてしまう手がある
  57. 57. Argument-Describing Messageの例 assertTrue( "Expected a > b but a was '" + a.toString() + "' and b was '" + b.toString() + "'", a.gt(b) ); assertTrue( "Expected b > c but b was '" + b.toString() + "' and    '" + c.toString + "'", b > c ); } c was
  58. 58. ご清聴 ありがとう ございました
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×