0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

RSpecの概要を調べる

Last updated at Posted at 2021-05-30

#はじめに
RSpecの基本的な勉強をしたので学習をまとめる

#RSpecとは
公式ドキュメントの翻訳

RSpec は、Ruby プログラマー向けのビヘイビア駆動開発ツールです。BDD は、テスト駆動開発、ドメイン駆動設計、受け入れテスト駆動計画を組み合わせたソフトウェア開発手法です。

これだけでは分からなかったので、他を参考にさせてもらうとテストフレームワークの1つ、ということみたい。

#メリット
自然言語(英語等)を併記するコードの特徴から可読性が上がる
TDDの観点からだとコードの変更時に予期せぬ不具合を防げる

#導入手順(Ruby)
プロジェクトの下準備

# ディレクトリの作成
mkdir project_ruby  # プロジェクトファイル
mkdir project_ruby/lib # テスト対象のファイルを入れるディレクトリ

# ディレクトリに移動
cd project_ruby

# bundleの初期化(Gemfile作成)
bundle init

# gemの追加とインストールを同時に行う
bundle add rspec

# RSpecの設定ファイルを作成(.rspec, spec/spec_helper.rb)
bundle exec rspec --init

次に読み込みの設定を行う。

spec/spec_helper.rb
#lib内のファイルを全て読み込むように設定する時
Dir[File.join(File.dirname(__FILE__), "../lib/**/*.rb")].each { |f| require f }

#特定のファイルを読み込む設定にする時
require_relative "../lib/読み込みたいファイル名.rb"

読み込み自体はテストコードに直接書いても挙動は変わらないようなので、共通設定はspec_helper.rbに書く方が重複せず済む。

これで準備完了。
lib にテスト対象のコードを書く
spec にテストコードを書く

ファイル 説明
lib テスト対象をまとめるライブラリ(ディレクトリ)
.rspec RSpec用の設定ファイル
spec RSpec用のディレクトリ
spec_helper.rb RSpecの動きをカスタマイズするファイル

導入手順(Rails)

プロジェクトの下準備

# プロジェクトの作成、postgresql指定とtestディレクトリを除外
rails new project_rails -d postgresql -T

# プロジェクトへ移動
cd project_rails

# DBの作成
rails db:create

Minitestを削除する明確な理由を見かけなかったが、そもそも格納するテストコードは別々のディレクトリ構造なので、必要ないから削除しているぽい。

続いて、Gemfileにgemを追加

#Rails用のフレームワークを追加
group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'rspec-rails'
end

最後にgemのインストールと設定ファイルの作成

# gemのインストール
bundle install

# RSpec用の設定ファイルの作成
rails g rspec:install

これで完了。
設定ファイルはRubyの時とは異なり、rails_helper.rbが追加されている。

ファイル 説明
.rspec RSpec用の設定ファイル
spec RSpec用のディレクトリ
spec/spec_helper.rb RSpecの動きをカスタマイズするファイル
spec/rails_helper.rb RSpecの動きをカスタマイズするファイル

#テストの実行

# 全てのRSpecを実行
bundle exec rspec

# 一部のRSpecを実行
bundle exec rspec spec/実行したいファイル.rb

#実行結果
=> No examples found.
=> Finished in 0.00052 seconds (files took 0.33436  seconds to load)
=> 0 examples, 0 failures

実行結果は下記の通り。

実行結果 説明
No example 実行結果の内容(記述していないので今回は何も表示されいない)
Finished テストにかかった時間を表す
0 examples 「0個のテストを実行した」を表す。itの数に比例。
0 failures 「0個のテストを失敗した」を表す。
0 pending 保留マークつけた箇所の警告を表す(上記にはない)

#失敗した実行結果
下記がテストの対象

lib/student.rb
#テスト対象
class Student
  attr_reader :name, :age

  def initialize(name:, age:)
    @name = name
    @age = age
  end

  def introduce
    "私は#{@name}です。年齢は#{@age}才です。"
  end
end

下記がテストコードとした時

spec/student_spec.rb
#テストコード
RSpec.describe Student do
  describe "initialize" do
    context "インスタンスが生成された時" do
      it "名前の値が正しいこと" do
        student = Student.new(name: "suzuki", age: 20)
        expect(student.name).to eq "suzuki"
      end

      it "年齢の値が正しいこと" do
        student = Student.new(name: "suzuki", age: 20)
        expect(student.age).to eq 10
      end
    end
  end

  describe "introduce" do
    it "正しい名前と年齢を含む値が返ること" do
      student = Student.new(name: "suzuki", age: 10)
      expect(student.introduce).to eq "私はsuzukiです。年齢は20才です。"
    end
  end
end

下記のような実行結果となる。

Student
  initialize
    インスタンスが生成された時
      名前の値が正しいこと
      年齢の値が正しいこと (FAILED - 1)
  introduce
    正しい名前と年齢を含む値が返ること (FAILED - 2)

Failures:

  1) Student initialize インスタンスが生成された時 年齢の値が正しいこと
     Failure/Error: expect(student.age).to eq 10

       expected: 10
            got: 20

       (compared using ==)
     # ./spec/student_spec.rb:11:in `block (4 levels) in <top (required)>'

  2) Student introduce 正しい名前と年齢を含む値が返ること
     Failure/Error: expect(student.introduce).to eq "私はsuzukiです。年齢は20才です。"

       expected: "私はsuzukiです。年齢は20才です。"
            got: "私はsuzukiです。年齢は10才です。"

       (compared using ==)
     # ./spec/student_spec.rb:19:in `block (3 levels) in <top (required)>'

Finished in 0.01333 seconds (files took 0.48402 seconds to load)
3 examples, 2 failures

Failed examples:

rspec ./spec/student_spec.rb:9 # Student initialize インスタンスが生成された時 年齢の値が正しいこと
rspec ./spec/student_spec.rb:17 # Student introduce 正しい名前と年齢を含む値が返ること

実行結果を見てみると、3 examples, 2 failures「3つのテストを実行して、2つ失敗した」とある。

expected: 10には、「期待していた値」が表示されている。
got: 20には、「実際の値」が表示されている。

つまり、ここの差異が失敗の原因を示している。

上記では1) Student initialize2) Student introduceの2つが表示されているので、2つの失敗が表示されていることになる。

また問題のある行数も具体的に記述されているので探しやすい。

#設定ファイルをカスタマイズ(.rspec)

.rspec
# rails_helperを読み込む
--require rails_helper

# 出力結果をドキュメント風に見やすくする
--format documentation

# 出力結果を色分けする
--color

必要に応じて.rspecに設定項目を追加。不要なものは削除する。

#テストコードの見方

.rb
#テスト対象を読み込むための記述
require_relative '../lib/ファイル名'

# 基本的な見方
RSpec.describe クラス名 do
  describe "対象(例:バリデーション)" do
    context "条件(例:データがA条件を満たす時)" do
      before do
      end
      it "期待する結果(例:保存できる)" do
        example().to eq 期待値
      end
    end
  end
end
コード 説明
RSpec.describe *** do ... end テストの宣言。これがないと正しく動作しない。
describe "***" do ... end テストの対象。
context "***" do ... end 条件別にグループ化(describeと機能的には同じ)
before do ... end 事前に処理を行うグループ。
it "***" do ... end 期待する処理と結果をコメント
example(X).to eq Y テストコード。
コメントの部分は . # '' "" など書き方が色々あるようだが挙動は変わらないため統一されていれば、どれでもいいみたい。

#マッチャ
引用

マッチャ(matcher)は「期待値と実際の値を比較して、一致した(もしくは一致しなかった)という結果を返すオブジェクト」のことです。
引用元:https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5

コードで言うと、exampleの行にある、epの部分のところみたい。

.rb
# 「Xの結果とYは等しい」を検証
expect(X).to eq Y

# 「Xの結果とYは異なる」を検証
expect(X).not_to eq Y

# be_falsey/be_truthyもマッチャ(言語仕様に合わせた真偽を判定)
expect(X).to be_truthy
expect(X).to be_falsey

# changeもマッチャ(XするとYが[Z~W]or[±Z]に変わることを期待する)
expect{X}.to change{Y}.form(Z).to(W)
expect{X}.to change{Y}.by(±Z)

# includeもマッチャ(「配列XにYが含まれている」を検証)
X = [Y, Z, W]
expect(X).to include Y

参考元の詳細が大変参考になった。
書籍も買ってみたので具体的な部分についてはまた記事にまとめたい。

参考元
RSpec/公式ドキュメント
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」
使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」
RailsじゃないRspec3環境を構築する方法

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?