Ruby

Rspec – プログラマにテストコードが設計であることを明確に意識させるドメイン特化言語

0

Rspecのことが分からなさすぎて、過去に調べたことを備忘録として残しておこうと思います。

Rspec

RspecはRuby言語をベースにした「ドメイン特化言語 (Domain Specific Language:DSL)」。ドメイン特化型言語 とは、特定の問題領域 (ドメイン) を記述するために設計された「言語」です。RSpecが特化しているドメインは「開発対象のプログラムの振舞を記述する」という領域。

『TDD』 の進め方と原則

TDD の進め方はいたってシンプルに3つ。

1. プロダクトコードを書く前にテストコードを書き、それが失敗することを確認する (レッド)
2. テストに成功するようにプロダクトコードを書く (グリーン)
3. プログラムの振る舞いを変えないように、プロダクトコードの重複などを整理する (リファクタリング)

TDDの原則もシンプルに3つ。

1. テストに失敗しない限り、プロダクトコードを書いてはいけない。
2. プロダクトコードはテストを通るように書く
3. テストは少しずつ書き進めていく

ソフトウェア

厳密にいえば、ソースコード、すなわちソフトウェア設計は次の2つの要素から構成される。

テストコード: プログラムがどのように振る舞うべきかを定義したもの
プロダクトコード: テストコードで定義された振る舞いを実装したもの

Rspecでは、TDDの文脈で開発を駆動する「テスト」をソフトウェア設計の要素であると位置付けている。
そしてRspecの狙いは「プログラマにテストコードが設計であることを明確に意識させることと、プログラマがテストコードをスムースに記述し実行できるようになること」。

そのために、Rspec は振舞定義用の DSL を提供し、様々なテスト関連ライブラリや周辺ツールとの連携を積極的に行い、「統合テスティング環境」となることを目指している。

コントローラーのテスト例

まずは、「assings」を使いたいから、下記を実行

そもそもコントローラーに書く必要があるテストは何?

コントローラーのテストで記述する必要があるのは基本的には下記の3つ。

①受信したリクエストに対して適切なレスポンスを返す
リクエストに対してHTTPレスポンスがステータスコード200を返しているかどうか?

②ビューで使用するのに必要なモデルオブジェクト(インスタンス)をロードする
リクエストされたURLから必要なモデルインスタンスをロードしているかどうか?
適切にインスタンス変数を取り出せているかどうか?

③レスポンスを表示するのに適切なビューを選択する
適切なテンプレートのビューを表示しているかどうか?

indexアクション

※参照URL:https://morizyun.github.io/ruby/rspec-rails-controller.html

describe

→describeにはテスト対象を書く。今回の場合は’GET #index’

インスタンス変数の代わりの「let」

上記の例でいうと、

のように書くと、 {create_list(:article,2)} の中の値を「articles」として参照して取り出すことができる。
ちなみに {create_list(:articles,2)}はarticlesというインスタンスを2回生成するという意味で、第二引数に繰り返す回数を数字で書く。
https://qiita.com/kindai_dai/items/617fd24b978f1ac1135f

before

example の前処理/ 後処理を記述するためのフック。Railsでいうところの、「before_action」のイメージ
上記の例でいうと、①〜③の検証をする前に {get: index, params:{}, session:{}}を実行している。

{①get: index, ②params:{}, ③session:{}} について
※参照:https://qiita.com/kuboon/items/8a7821e06094706d121c

①get :index 第一引数はアクション名であり、実際の url とはまったく関係がない。
②get :show, id: 3 のようにして、 params[:id] に値を直接渡すことができる。
③post :create, session: {user_id: 5}のようにして、 session: {user_id:} に値を直接渡すことができる。
セッションについて https://www.sejuku.net/blog/33677

assignsメソッド

→assignsメソッドはコントローラーのインスタンス変数をテストするメソッド。引数にインスタンス変数をシンボル型で渡す。

matchマッチャ/match_arrayマッチャ

→文字列・ハッシュ・配列の検証に用いるマッチャ。
matchマッチャで配列を検証すると、配列の順番も期待値(expect)と一致している必要がある。
一方、match_arrayマッチャで検証した場合は、要素の個数と各要素の同値性だけを検証し、順番は検証しない。

コントローラのテストで利用できる機能(一例)

■get(action, params={})
指定したアクションへ GET リクエストを送信。

■response()
レスポンスオブジェクトへのアクセサです。レスポンスオブジェクトは HTTP ステータスコードや使用したテンプレートの情報を保持。

■assigns[variable_name]
コントローラのインスタンス変数 @variable_name に代入されたオブジェクトを取得します。キーには “@” を除いたものを文字列またはシンボルで指定。

■post(action, params={})
指定したアクションへ POST リクエストを送信します。パラメータの指定方法は get と同じです。同様に、put や delete もある。

■session()
セッションオブジェクトへのアクセサです。セッション変数の設定やセッション ID を取得する際に利用。

■request()
リクエストオブジェクトへのアクセサです。リクエストの MIME-Type を設定する場合などに利用。

createアクション

この記事が分かりやすい
URL:https://forest-valley17.hatenablog.com/entry/2018/09/29/174446

※show/edit/newは下記URLを参照。
URL:https://morizyun.github.io/ruby/rspec-rails-controller.html

createアクションで、if @変数.save のように条件分岐をしている場合は、
下記のようにcontextで条件別にグループ化する。

以下、記述例

sign_inを使用して、ログイン状態をシミュレートしてテストをする場合は
spec/rails_helper.rbに下記記述を追加する必要がある。

change + from / to / by

例文

changeで置き換えると、、、

読み方は下記の通り

expect{ X }.to change{ Y }.from(A).to(B) = 「X すると Y が A から B に変わることを期待する」

from().to()は「by」で書き換えることもできる、、、

配列要素の個数はsizeじゃなくて、countも使える

このように、change マッチャを使うと、「Xに対するある操作が、一見無関係なYに影響を与える」といった検証内容を簡潔に表現することができる。

モック(Mock)

何らかの理由で本物のプログラムが使えない、もしくは使わない方がよいケースでモックが使われる。
使い道としては、外部のAPIを利用しなければならない場合など。
例えば、TwitterのAPI(gem)経由でツイートするプログラムをテストする場合は、テストコードの内容がそのまま
全世界にツイートされてしまう。それは嫌だ。
ということで、モックを使えば、Twitterと同じ機能を持ち且つテストコードでのみ起動するプログラムを作ることができる。

以下、簡単な例

■Ruby.controller.rb

 

■Ruby.Mock.rb

そのほか、詳細は下記参照

※参考ページ※ これらを読んだら基本的なRspecのことは分かるはず!
https://morizyun.github.io/ruby/rspec-rails-controller.html
https://qiita.com/jnchito/items/42193d066bd61c740612
https://qiita.com/jnchito/items/640f17e124ab263a54dd
https://qiita.com/jnchito/items/a4a51852c2c678b57868
https://magazine.rubyist.net/articles/0021/0021-Rspec.html
https://qiita.com/namitop/items/bf455f8383181ff6edf3
https://magazine.rubyist.net/articles/0023/0023-Rspec.html#%E6%B0%B4%E5%B9%B3%E5%88%86%E5%89%B2%E3%82%A2%E3%83%97%E3%83%AD%E3%83%BC%E3%83%81%E3%81%A8%E5%9E%82%E7%9B%B4%E5%88%86%E5%89%B2%E3%82%A2%E3%83%97%E3%83%AD%E3%83%BC%E3%83%81
https://forest-valley17.hatenablog.com/entry/2018/09/29/174446
https://qiita.com/morrr/items/f1d3ac46b029ccddd017
https://qiita.com/muran001/items/436fd07eba1db18ed622

0
ABOUT ME
chopes
前職では、人材業界で法人営業・キャリアアドバイザー・大阪責任者をしていました。他にも、新入社員の研修策定と育成、面談者の集客におけるスカウト業務や中途採用の面接官、新卒採用の2次選考官、インターンシップのメンターとしてプログラムに参加していました。退職後は、未経験でエンジニアになるためにスクールに通学して勉強。2ヶ月の転職活動を経て、今春からRailsエンジニアとして第二のキャリアを歩むことになりました。主に学習記録や未経験エンジニアについてアウトプットしていきたいと思います! 以下、Twitterアカウントですので、気軽にフォローしてください! Twitter:@chopesu_se