RSpecの基本的な部分を勉強してみた
ブログだいぶサボってました…。
いよいよまずいと思ったので久々に更新です。
今回はRSpecについてだらっと書きます。
Ruby on RailsでWebアプリを作る営みをしているのですが、テストをかなりおざなりにしていた+テストの書き方がイマイチわからない状態というブログ更新を滞ったよりもまずい状況だったので勉強しました。
ざっくり学んだことをもはや個人的なメモとしてだらだら書いていきます。
がっつり理解できているわけではないので内容的に曖昧なところもあるので悪しからずです…。
RSpecとはなんぞや?
Rubyのテストフレームワークの一つで、テストを書くのに特化したDSLとかいうやつみたいです。
RSpecを使うために
- rspec --initで.rspecとspecディレクトリが作成される
- テストを記述したファイルはspecフォルダに格納
- xxxx_spec.rbみたいなファイル名にする
- テスト実行はrspecコマンドを使用する
- -fdオプションをつけるとテスト毎の成否が見れるようになる
RSpecの基本的な書き方
RSpec.describe "テスト名(クラス名とか)" do before do end it "テストケース(メソッドとか)" do end it "テストケース" end
beforeメソッド
- テスト実施前の初期処理を書く(インスタンス生成とか)
- beforeで生成した変数は変数の前に@をつけてインスタンス変数のように宣言する必要あり
- beforeの引数には:exampleと:contextがある
- :exampleは各exampleの前に実行される(引数省略で:exampleとなる)
- :contextはdescribeの中の最初の一回目に実行される
example
- it 〜 endのこと(1テストケースを指す?)
- itはexample / specifyと書くことも可能
- テストケースのところに書く文と文脈があうようなものを適宜選択する
- ブロックを記載しないとpending(棚上げ)となる
describe / context
- テスト対象を指定する(exampleのグループ化ができる)
- describeもdescribeの中で入れ子にできる
- トップレベルのdescribeはクラス名を書く
- describeと同様に使うことができる
- describeが物、contextが状況という使い分けをする
matcher
期待する振る舞いを指定する記号を指す
matcher一覧
- eq(x):xと等しいか
- not_eq(x):xと等しくないか
- be [true/false]:trueかfalseか
- be < x:xより小さいか
- be_between(x, y).inclusive:数値がxとyの範囲内か(xとyも範囲に含む)
- respond_to(:{メソッド名}):そのメソッドが存在しているか
- Rubyの特徴を生かした書き方
- 例として結果がintegerかどうか調べるテスト を書く
expect(obj.add(2,3).integer?).to be true
上記の書き方を
expect(obj.add(2,3)).to be_integer
と書くことができる
- 例として結果がintegerかどうか調べるテスト を書く
subject
RSpec.describe Sample do it { sample = Sample.new expect(sample.add(2, 3)).to eq(5) } end
これを
RSpec.describe Sample do it { expect(subject.add(2, 3)).to eq(5) } end
にできる。
しかし、このままだとテストケースが長くなった時にsubject
ってなんだっけとなってしまうので以下のように書く。
RSpec.describe Sample do subject(:sample) { Sample.new } it { expect(sample.add(2, 3)).to eq(5) } end
subject
にシンボルを渡して{}内でnewしてやるとsample
をインスタンスとして使えるようになる。
before
を使えば良いじゃないかという話もあるがbefore
だとexample内でインスタンス変数を使う必要が出るためsubject
の方がスッキリする。(好みの問題的な側面もあるらしいが…)
method stub
メソッドをまだ実装していないけどテストに使用したいよーという場合に使う。
ex)Userモデルから名前を取得するnameメソッドを使いたいけどまだできてないよーっていう場合
RSpec.describe Sample do it { #test doubleの呼び出し #doubleの引数はなくても良いが失敗した時などに便利なので書いておく user = double('user') #nameメソッドが呼び出されたら強制的にtanakaを返すようにする allow(user).to receive(:name).and_return('tanaka') sample = Sample.new expect(sample.add(5, user.name)).to eq('5 by tanaka') } end
message expectation
呼ばれなかったらテストが失敗する。
ある処理の前に確実にある処理が走っていることを保証したい場合に使用する。
ex)ログの処理を書いていなけどログを書く処理が各区実に呼ばれたかテストしたいよーっていう場合
RSpec.describe Sample do it { #ロガーのtest doubleを作成する logger = double('logger') #loggerのlogメソッドが呼ばれていることを確認する expect(logger).to receive(:log) #sampleクラスでloggerインスタンスを使用する想定 sample = Sample.new(logger) expect(sample.add(5, user.name)).to eq('5 by tanaka') } end
あー、久々に記事書きましたー。
文章書くのは訓練しないとどんどん書けなくなりますね…
これからは週に最低1記事を目標にブログ頑張ります!