Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第10章 テストに聞いてみる #14

Merged
merged 18 commits into from
Nov 8, 2017
Merged

第10章 テストに聞いてみる #14

merged 18 commits into from
Nov 8, 2017

Conversation

at-grandpa
Copy link
Owner

@at-grandpa at-grandpa commented Nov 7, 2017

TODO

  • $5 + 10 CHF = $10(レートが2:1に場合)
  • $5 * 2 = $10
  • amountをprivateにする
  • Dollarの副作用どうする?
  • Moneyの丸め処理をどうする?
  • equals
  • hashCode
  • nullとの等価性比較
  • 他のオブジェクトとの等価性比較
  • 5CHF*2=10CHF
  • DollarとFrancの重複
  • equalsの一般化
  • timesの一般化
  • FrancとDollarを比較する
  • 通貨の概念
  • testFrancMultiplicationを削除する?

@at-grandpa
Copy link
Owner Author

at-grandpa commented Nov 7, 2017

timesがかなり似ているが、まだ一致はしていない。が、まだその一致方法はまだわからない。後戻りもあるかも。

@at-grandpa
Copy link
Owner Author

一回、Franc#timesをインライン化。FactoryMethodを適用したのに、これは後戻り。

テストは通る。

 crystal spec' <

....

Finished in 632 microseconds
4 examples, 0 failures, 0 errors, 0 pending

@at-grandpa
Copy link
Owner Author

currencyをプロパティ化した。テストは通る。

 crystal spec' <

....

Finished in 574 microseconds
4 examples, 0 failures, 0 errors, 0 pending

@at-grandpa
Copy link
Owner Author

適当にcurrencyをhogeにしたが、テストが通ってしまった。

 crystal spec' <

....

Finished in 718 microseconds
4 examples, 0 failures, 0 errors, 0 pending

歩幅が大きかったようだ。

@at-grandpa
Copy link
Owner Author

ちょっと調査。

@at-grandpa
Copy link
Owner Author

あー、==ではcurrencyのチェックをしていないからか。timesで生成したFrancとFactoryMethodで生成したFrancとでは、amountも同じだし、classも同じなので通ってしまう。

このままいっていいか、ちょっと様子見。

@at-grandpa
Copy link
Owner Author

あー、さらっと先を読んだら、この部分を言及していた。読み進めてok。

@at-grandpa
Copy link
Owner Author

FrancのtimesでMoneyをnewしてみる。試してみた。

コンパイルは落ちる。

 crystal spec' <

Error in line 1: while requiring "./spec/money_spec.cr"

in spec/money_spec.cr:23: instantiating 'MoneyPackage::Franc#times(Int32)'

      five.times(2).should eq MoneyPackage::Money.franc(10)
           ^~~~~

in src/money_package/franc.cr:8: instantiating 'MoneyPackage::Money:Class#new(Int32, String)'

      MoneyPackage::Money.new(@amount * multiplier, @currency)
                          ^~~

in src/money_package/money.cr:3: can't instantiate abstract class MoneyPackage::Money

    def initialize(@amount : Int32, @currency : String)
    ^

Moneyはabstractクラスなのでnewできない。

@at-grandpa
Copy link
Owner Author

Moneyを具象クラスにする。そしてtimesを作成する。コンパイラを通す。

@at-grandpa
Copy link
Owner Author

at-grandpa commented Nov 8, 2017

Moneyを具象クラスにしたら、コンパイルは通るがテストが落ちる。

 crystal spec' <

..F.

Failures:

  1) MoneyPackage testFrancMultiplication() 掛け算を計算できること
     Failure/Error: five.times(2).should eq MoneyPackage::Money.franc(10)

       Expected: #<MoneyPackage::Franc:0x104767b40 @amount=10, @currency="CHF">
            got: #<MoneyPackage::Money:0x104767b60 @amount=10, @currency="CHF">

     # spec/money_spec.cr:23

Finished in 852 microseconds
4 examples, 1 failures, 0 errors, 0 pending

Failed examples:

crystal spec spec/money_spec.cr:21 # MoneyPackage testFrancMultiplication() 掛け算を計算できること

何を言っているかわからないので、to_sメソッドを作成してみる。ここはcrystalだとどうなんだろう。

@at-grandpa
Copy link
Owner Author

crystalのspecでは、オブジェクトのプロパティも表示してくれているので、べつに出力をいじる必要はないだろう。

やめる。

@at-grandpa
Copy link
Owner Author

テストのエラーをみてみると、クラスが異なっている。これは==がおかしい。クラスではなく、通貨が等しいかを見なければならない。

@at-grandpa
Copy link
Owner Author

ここでテストを書きたいが、今はレッドだ。レッドで新しいテストの追加は避けたい。一旦グリーンに戻す。

@at-grandpa
Copy link
Owner Author

もどした。

 crystal spec' <

....

Finished in 1.27 milliseconds
4 examples, 0 failures, 0 errors, 0 pending

@at-grandpa
Copy link
Owner Author

Franc(10, "CHF")とMoney(10, "CHF")が等価になってほしいのに、等価ではないことが問題。テストコードを書こう。

@at-grandpa
Copy link
Owner Author

テストは落ちる。

 crystal spec' <

....F

Failures:

  1) MoneyPackage testDifferentClassEquality() クラスが違っても通貨で等価比較できること
     Failure/Error: (MoneyPackage::Money.new(10, "CHF") == MoneyPackage::Franc.new(10, "CHF")).should be_true

       Expected: true
            got: false

     # spec/money_spec.cr:35

Finished in 1.8 milliseconds
5 examples, 1 failures, 0 errors, 0 pending

Failed examples:

crystal spec spec/money_spec.cr:34 # MoneyPackage testDifferentClassEquality() クラスが違っても通貨で等価比較できること

@at-grandpa
Copy link
Owner Author

FrancのtimesでMoneyをnewしてもテストが通るようになった。

 crystal spec' <

.....

Finished in 1.4 milliseconds
5 examples, 0 failures, 0 errors, 0 pending

@at-grandpa
Copy link
Owner Author

Dollarを同様に変更しても動いた。

@at-grandpa
Copy link
Owner Author

テストは通る。

@at-grandpa
Copy link
Owner Author

かなり綺麗になったな。

@at-grandpa
Copy link
Owner Author

サブクラスを消す準備ができた。

振り返り。

  • サブクラスたちのtimesメソッド実装の際をなくすために、まずはメソッド呼び出しをインライン化し、次にベタ書きの値を変数に置き換えた
  • デバッグ用のto_sメソッドをテストを書かずに実装した
  • Francの代わりにMoneyを返す変更を試み、動くか動かないかはテストに聞いてみた
  • 実験的な変更を巻き戻し、もう一つテストを書いた。再度テストを通るように実装することで、今回の実験を成功に導いた

@at-grandpa
Copy link
Owner Author

at-grandpa commented Nov 8, 2017

TODO

  • $5 + 10 CHF = $10(レートが2:1に場合)
  • $5 * 2 = $10
  • amountをprivateにする
  • Dollarの副作用どうする?
  • Moneyの丸め処理をどうする?
  • equals
  • hashCode
  • nullとの等価性比較
  • 他のオブジェクトとの等価性比較
  • 5CHF*2=10CHF
  • DollarとFrancの重複
  • equalsの一般化
  • timesの一般化
  • FrancとDollarを比較する
  • 通貨の概念
  • testFrancMultiplicationを削除する?

@at-grandpa
Copy link
Owner Author

感じたこと。

  • やはり細かい感じがするが、これは個々人の歩幅の問題だろう
  • 「こういう歩幅にもできるよ」という知見
  • とりあえずできるか実装してみて、「テストに聞く」というのがこの章の言いたいこと
  • わかる

@at-grandpa at-grandpa merged commit 45e0b62 into master Nov 8, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants