beforeブロックを使った共通化
beforeブロックを使うことでdescribeやcontextブロックの内部で各テスト実行前に共通のインスタンス変数をセットアップできます。
1 2 3 4 5 6 7 8 9 10 11 |
describe [テスト対象],type:[specの種類] do context [状態] do before do [事前準備] end it [仕様] do [期待動作] end end end |
beforeブロックによる共通化のデメリット
- beforeブロックではテストを実行するたびに毎回実行されるのでテストに予期しない影響を及ぼす可能性がある。
- 要件が増えるに連れてテストの可読性が悪くなる。
beforeブロックではテストを実行するたびに毎回実行されるのでテストに予期しない影響を及ぼす可能性がある。
全てのテストが使わない余計なデータを持つことになります。そのため予期しない副作用を起こす可能性があります。
let(共通処理の変数化)
Rspecの共通化は基本的にbefore句にて行うことができるとは思いますが、共通化したい内容が必ずしも固定値じゃ無い場合に使えるのがletで変数的に処理を共通化することができる機能になります。letは遅延読み込み(呼ばれた際に初めてデータを読み込む)であり、beforeブロックの外部で呼ばれるのでセットアップに必要なテスト構造を減らすことが可能です。
letの構文
下記のように記述します。
1 |
let(:定義名) {定義の内容、つまりRspecで行う処理} |
定義名と記述した箇所が実際にRspecのテストコード内で使えるオブジェクトの変数になります。
例
1 |
let(:user) {FactoryBot.create(:user)} |
例えば、上記のようにすることでuserという変数に対してFactoryBotのテンプレートで定義したDBの登録情報を格納することができます。
letが呼ばれるタイミング
letが呼ばれるタイミングはブロック内で初めて変数として呼ばれたタイミングになります。なので、beforeブロックで変数を定義する場合とは異なりインスタンス変数としなくても変数を参照することが可能です。一度も呼ばれないletは実行されることは無いので注意です。例えば、contextブロックの中に記載したletは必ず呼ばれますが、describe直下に配置したletは変数として実際に別のコードで使われルことがない限りは実行されないです。
letは上書きできる。
letで定義した変数は入れ子になっているテストコードの場合はより下の階層で定義したletにて上書きすることが可能です。基本的にはこういう値が良いが、数少ない特定の場合だけは変えたいと言った場合には使える機能です。
let!について
letは変数として別のコードで呼んであげないと使われないですが、let!として定義すればbeforeの前に強制的に実行させることが可能です。要は遅延読み込みを強制的に解除して変数を読み込ませることが可能です。あまり使う機会がないかもしれませんが、既存のテストコードの問題で使わざる追えないケースがあるかもしれませんので知っておくと良いでしょう。
let!の用途
letで定義した変数はそのブロック内で1度でも使わない限りは初期化されることはありません。なので、変数の値としては使わないが変数の件数をカウントしたい場合とかの用途では使うことができます。ただ、beforeブロックと機能は同じですし「!」は小さな変化のため読み間違えてしまいやすいのでもし使う場合はbeforeブロックを使うことも検討しましょう。
shared_context(contextの共通化)
shared_contextを使うと「複数のテストファイルの処理」の共通化を行うことができます。
共通化
1 2 3 |
RSpec.shared_context "共通化名" do 処理内容 end |
呼び出し側
1 |
include_context "project setup" |
shared_example(itの共通化)
shared_exampleを使うと「it内の処理」の重複を共通化する機能です。
共通化後の書き方
下記のようにitの処理を共通化します。
1 2 3 |
shared_examples_for '共通処理名' do it { 共通処理内容 } end |
呼び出し方
下記のように呼び出します。
1 |
it_behaves_like '共通処理名' |
この記事へのコメントはありません。