VCRでレスポンスをERBで設定する

自分がしらなかっただけですが、便利だったので。

VCRは外部へのリクエストを記録し、テスト時に外部リクエスト呼び出しをモックしてれるツールです。
VCR自体はカセット(casset)と呼ばれるフィクスチャを記録/再生する機能が主で、モック自体は
webmock/faradayなどのモックライブラリを内部で使用しています。

[vcr/vcr: Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.](https://github.com/vcr/vcr)

例えば、下記のようなstripeのapi実行を伴うようなテストケースをVCR.use_cassetteという
ブロックの中実行すると、指定したパスにレクエスト/レスポンスを記録したymlを保存してくれます。
(そして2回目以降はymlを読んで、リクエストにマッチしたら記録されているレスポンスを返してくれます)

```ruby
describe CancelOrder do
  it 'updates status of order/history' do
    order = create(:order, :with_payment, :fixed)

    VCR.use_cassette 'stripe/refund' do
      CancelOrder.new(order).execute
      # charge = Stripe::Charge.retrieve(order.payment.id)
      # charge.refund
    end

    expect(order.status).to eq ::Order.statuses[:canceled]
    expect(order.order_histories.last.status).to eq ::Order.statuses[:canceled]
  end
end
```



```stripe/refund.yml
---
http_interactions:
- request:
    method: get
    uri: https://api.stripe.com/v1/charges/ch_16gwnzBPgBFgcl8jurjBMKFq
    body:
      encoding: US-ASCII
      string: ''
    headers:
      X-Stripe-Client-User-Agent:
      - '{"bindings_version":"1.23.0","lang":"ruby","lang_version":"2.1.4 p265 (2014-10-27)","platform":"x86_64-linux","engine":"ruby","publisher":"stripe","uname":"Linux
        version 2.6.32-358.el6.x86_64 (mockbuild@c6b8.bsys.dev.centos.org) (gcc version
        4.4.7 20120313 (Red Hat 4.4.7-3) (GCC) ) #1 SMP Fri Feb 22 00:31:26 UTC 2013"'
  response:
    status:
      code: 200
      message: OK
    headers:
      Stripe-Version:
      - '2015-07-07'
    body:
      encoding: UTF-8
      string: |
        {
          "id": "ch_16gwnzBPgBFgcl8jurjBMKFq",
          "object": "charge",
          "amount": 37591,
          "amount_refunded": 37591,
          "application_fee": null,
          "balance_transaction": null,
          ….
```

まあ、これだけでも便利なのですが、そのままだと異なるデータを返したい場合に別のカセットを
定義しないといけなくなります。

また、APIによってはオブジェクトごとにリクエストのパラメーターが変わったりタイムスタンプが
追加されたりするので、そのままだとモックにマッチしなくなります。

※これはmatch_request_on: [:path]のようなかたちでパラメーターを渡すとマッチの条件を変更することで対応できますが([Matching on Path](
http://www.relishapp.com/vcr/vcr/v/3-0-3/docs/request-matching/matching-on-path))

VCRはyaml内にerbも書けるので下記のようにタグを埋め込んで、呼び出し時にアサイン変数を渡せば
動的にレスポンスを変更できます。

Dynamic ERB cassettes
http://www.relishapp.com/vcr/vcr/v/3-0-3/docs/cassettes/dynamic-erb-cassettes


```stripe/refund.yml
---
http_interactions:
- request:
    method: get
    uri: https://api.stripe.com/v1/charges/<%= charge_id %>
  response:
    status:
      code: 200
      message: OK
    headers:
      Stripe-Version:
      - '2015-07-07'
    body:
      encoding: UTF-8
      string: |
        {
          "id": "<%= charge_id %>",
          "object": "charge",
          "amount": <%= amount %>,
          "amount_refunded": <%= amount %>,
          "application_fee": null,
          "balance_transaction": null,
          ….
```

```
describe CancelOrder do
  it 'updates status of order/history' do
    order = create(:order, :with_payment, :fixed)

    VCR.use_cassette 'stripe/refund', erb: { charge_id: order.payment.charge_id, amount: 3000 } do
      CancelOrder.new(order).execute
    end

    expect(order.status).to eq ::Order.statuses[:canceled]
    expect(order.order_histories.last.status).to eq ::Order.statuses[:canceled]
  end
end
```

※テストコードがあんまいい例じゃなくてすんません。

そもそもVCRを使うとあんまり外部ライブラリの実装を気にせず、スタビーなテストコードが減らせますが、
erbをつかうとさらに

* フィクスチャ(cassette)を数を抑制できる
* お手軽にAPIのレスポンスを変更できる

ので、いいかもしれません。