消費税改正に備える（テスト）

## はじめに
[消費税改正に備える](https://qiita.com/ken1flan/items/3a2fa9647cc8088fe88f)っていったって、お金のことなんだからテスト欲しいよねって思って、テストのほうも準備しました。

テストのソースは長くなりがちなので、[こちら](https://github.com/ken1flan/with_tax_sample/tree/master/spec)を見てみてください。

## 方針
テストはモジュールのほうでガッチリやって、モジュールをextendしたクラスのほうはメソッドが使えることくらいを確認するくらいにします。

## [モジュールのテスト](https://github.com/ken1flan/with_tax_sample/blob/master/spec/with_tax_spec.rb)

モジュールのテストで、ちょっとおもしろそうなところだけ、ピックアップします。

### [テストごとにちゃんと作り直されるクラス](https://github.com/ken1flan/with_tax_sample/blob/master/spec/with_tax_spec.rb#L3-L14)

クラス定義を`let`で変数のようにしてるところはちょっとおもしろいと思っています。RubyはクラスもClassクラスのオブジェクトなので、こんな書き方ができて、これだとテストごとに毎回定義されるので、いろいろとテストがやりやすくなったなあと思っています。


```ruby
let(:klass) do
  Class.new do
    extend WithTax

    attr_accessor :name, :price
    attr_with_tax :price

    def initialize(name, price)
      @price = price
    end
  end
end
```

### [実行日の固定化](https://github.com/ken1flan/with_tax_sample/blob/master/spec/with_tax_spec.rb#L17-L18)

実行したときによって結果が変わるテストは、実行日を止めておいたほうがよいと思っています。
たまにmasterのCIが落ちてワタワタしますが、実行日を決めておかなかったことが原因だったことが一度や二度ではなかったです。
あと、戻し忘れてほかのテストが落ちたり落ちなかったりするようになることも多かったので、止めたらすぐに戻すコードを書く癖をつけています。

なお、ここでは[Timecop](https://github.com/travisjeffery/timecop)を使っていますが、railsを使っている場合であれば、[travel_to](https://railsguides.jp/testing.html#%E6%99%82%E9%96%93%E3%81%AB%E4%BE%9D%E5%AD%98%E3%81%99%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E3%83%86%E3%82%B9%E3%83%88%E3%81%99%E3%82%8B)などがあるので、そちらがいいと思います。

```ruby
before { Timecop.freeze(Date.parse(execution_date)) }
after { Timecop.return }
```

### [`.attr_with_tax`がちゃんとメソッドを足せた？](https://github.com/ken1flan/with_tax_sample/blob/master/spec/with_tax_spec.rb#L20-L30)

`respond_to`マッチャーで、[`attr_with_tax`を指定している`price`](https://github.com/ken1flan/with_tax_sample/blob/master/spec/with_tax_spec.rb#L8)には`price_with_tax`が設定されていること、指定していない`name`には`name_with_tax`が存在しないことを確認しています。

```ruby
describe 'メソッドの追加' do
  let(:sample_item) { klass.new('Sample Item', 123) }

  it '#price_with_taxが存在すること' do
    expect(sample_item).to respond_to(:price_with_tax).with(1).argument
  end

  it '#name_with_taxが存在しないこと' do
    expect(sample_item).not_to respond_to(:name_with_tax)
  end
end
```


### [追加したメソッドはちゃんと動いてる？](https://github.com/ken1flan/with_tax_sample/blob/master/spec/with_tax_spec.rb#L32-L195)

足されることは確認できたので、今度は足されているメソッドが期待通り動くのか確認します。
このあたりは、ごく普通のテストみたいに書けました。

#### 小数点以下の処理
小数点以下を切り捨てる仕様にしたので、小数点以下が０．５未満の例と0.5以上の例を挙げて確認しました。

```ruby
describe '小数点以下の処理' do
  subject { sample_item.price_with_tax }

  let(:sample_item) { klass.new('Sample Item', price) }
  context 'price = 123のとき' do
    let(:price) { 123 }

    it '135.3->135(切り捨て)になること' do
      is_expected.to eq 135
    end
  end

  context 'price = 345のとき' do
    let(:price) { 345 }

    it '379.8->379(切り捨て)になること' do
      is_expected.to eq 379
    end
  end
end
```

#### 税率
税率は実行日や指定日によって変わります。
2019/10/01の改正で10%になったので、その前日は8%で計算されていることなど、改正日の前後をピックアップして値のテストを行いました。

中身は長いので[こちら](https://github.com/ken1flan/with_tax_sample/blob/master/spec/with_tax_spec.rb#L54-L195)でみてください。


## [モジュールを利用しているクラスのテスト](https://github.com/ken1flan/with_tax_sample/blob/master/spec/sample_item_spec.rb)
モジュールのほうでがっちりテストしているので、ここでのテストは`#price_with_tax`が存在することを確認するのみとしました。

```ruby
RSpec.describe SampleItem do
  describe '#price_with_tax' do
    subject { SampleItem.new('Sample Item', 123) }

    it '#price_with_taxが利用できること' do
      is_expected.to respond_to(:price_with_tax).with(1).argument
    end
  end
end
```

## 最後に
先にも書きましたが、「クラスはClassクラスのオブジェクト」が好きで、こういうのを書くとRubyっていいなって実感します。