ちょっとだけ嬉しくなるrspecの小ネタ

## はじめに

この記事は [LIFULLその2 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/lifull2) の20日目の記事です。

業務で rspec のテストコードを書いたときの些細な発見を整理してまとめます。
オムニバスな感じで、ひとつくらい読者様の発見があれば幸せです。

## rspecメモ

### subject の工夫

DRYなテストコードを書くためには `subject` が必須です。
ということはいろんなところで書かれていますが
`subject` に名前がつけられるということを [Better Specs](http://www.betterspecs.org) で学びました。 ※下記は引用

```rb
subject(:hero) { Hero.first }
it "carries a sword" do
  expect(hero.equipment).to include "sword"
end
```

テスト対象がつまり何なのかを直接的に書けるため
`subject` という抽象的な表現より可読性は高く思えます。

`subject` も `let` と同様に遅延評価される処理で
`let!` と同様に `subject!` と書くことで、example の直前に評価させることもできます。

### example の書き方

[ドキュメント](https://relishapp.com/rspec/rspec-core/v/3-8/docs) の最初には `it` で example が書かれていますが
他にも `example` や `specify` という別名が存在します。
どの書き方でも挙動は同じです。

```rb
describe Account do
  it "has a balance of zero when first opened" do
  end

  example "has a balance of zero when first opened" do
  end

  specify "has a balance of zero when first opened" do
  end
end
```

じゃあなんで3つあるのかと思って[コード](https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/example_group.rb
)内のコメントを読んでみると

| メソッド | コメント | 意訳 |
|:-----------------:|:------------------:|:------------------:|
|example| Defines an example within a group. | exampleを定義します |
|it| Defines an example within a group. <br> This is the primary API to define a code example. | これがプライマリなAPIです |
|specify| Defines an example within a group. <br> Useful for when your docstring does not read well off of `it`.| docstringが `it` をうまく読めないときに便利です |

（ワンライナーとか書くならどうせ選択肢はなくなるので）
全体的に `it` を使っていて問題ないと思いますが
日本語で自然な記述を目指すのであれば `example` が望ましいように見えます。

### 実行するテストケースのフィルタリング

１ファイルが小さい単位で作られていたら幸せですが
歴史を積み重ねたファイルには多くのテストケースが存在します。
「１ケースだけ確認したいのに…」という場合にケースを絞る方法がいくつかあります。

- [focus (Inclusion filters)](https://relishapp.com/rspec/rspec-core/v/3-8/docs/filtering/inclusion-filters): focusと明示したケースだけを実行する
- [実行時のtagオプション](https://relishapp.com/rspec/rspec-core/v/3-8/docs/command-line/tag-option): 実行したいケースにタグを付けておいて部分的に実行する
- [実行時のexampleオプション](https://relishapp.com/rspec/rspec-core/v/3-8/docs/command-line/example-option): 名前を指定したケースだけ実行する

もっと手軽に一部ケースだけを実行する方法として、[行数指定](https://relishapp.com/rspec/rspec-core/v/3-8/docs/command-line/line-number-appended-to-file-path)があります。
※下記は引用したコードを少しだけ書き直したもの

```rb
RSpec.describe "outer group" do
  it "example in outer group" do
  end

  describe "nested group" do
    it "first example in nested group" do
    end

    it "second example in nested group" do
    end
  end
end
```

2行目の `example in outer group` だけ実行

```sh
$ bundle exec rspec --format d test_spec.rb:2
Run options: include {:locations=>{"./test_spec.rb"=>[2]}}

outer group
  example in outer group

Finished in 0.00369 seconds (files took 0.14879 seconds to load)
1 example, 0 failures
```

5行目にある `nested group` 内だけを実行

```sh
$ bundle exec rspec --format d test_spec.rb:5
Run options: include {:locations=>{"./test_spec.rb"=>[5]}}

outer group
  nested group
    first example in nested group
    second example in nested group

Finished in 0.00342 seconds (files took 0.13323 seconds to load)
2 examples, 0 failures
```

9行目にある `second example in nested group` だけを実行

```sh
$ bundle exec rspec --format d test_spec.rb:9
Run options: include {:locations=>{"./test_spec.rb"=>[9]}}

outer group
  nested group
    second example in nested group

Finished in 0.00342 seconds (files took 0.13009 seconds to load)
1 example, 0 failures
```

一部だけを実行する方法としてはもっとも楽ではないかと思います。
（よく見たらヘルプにも記載されていました）

> you can select individual examples by appending the line number(s) to the filename:
> rspec path/to/a_spec.rb:37:87

## おわりに

小ネタでした。事務的にテストコードを書くのではなく
実行結果がより仕様らしく見えるように、自然な英語になるように
また、楽にメンテできるように心がけたいです。