🎃

RSpecの`eq`と`be`の違いを完全理解!初心者向け徹底解説

に公開

RSpecのeqbeの違いを完全理解!初心者向け徹底解説

RSpecでテストを書いている時、eqbeのどちらを使えばいいか迷ったことはありませんか?この記事では、この2つのマッチャーの違いを具体例とともにわかりやすく解説します。

TL;DR(要約)

  • eq: 値の等価性をチェック(==と同じ)
  • be: オブジェクトの同一性をチェック(equal?と同じ)

基本的な違い

eqマッチャー

eq値の等価性を比較します。Rubyの==メソッドと同じ動作をします。

# 値が同じかどうかをチェック
expect(1 + 1).to eq(2)
expect("hello").to eq("hello")
expect([1, 2, 3]).to eq([1, 2, 3])

beマッチャー

beオブジェクトの同一性を比較します。Rubyのequal?メソッドと同じ動作をします。

# 同じオブジェクトかどうかをチェック
str1 = "hello"
str2 = str1
expect(str2).to be(str1)  # 同じオブジェクトなのでパス

具体例で理解しよう

文字列の場合

RSpec.describe "文字列の比較" do
  it "eqとbeの違い" do
    str1 = "hello"
    str2 = "hello"
    str3 = str1

    # 値は同じだが、異なるオブジェクト
    expect(str1).to eq(str2)     # ✅ パス(値が同じ)
    expect(str1).not_to be(str2) # ✅ パス(異なるオブジェクト)

    # 同じオブジェクトを参照
    expect(str3).to eq(str1)     # ✅ パス(値が同じ)
    expect(str3).to be(str1)     # ✅ パス(同じオブジェクト)
  end
end

数値の場合

RSpec.describe "数値の比較" do
  it "小さな整数の場合" do
    a = 1
    b = 1
    
    # 小さな整数はRubyが同じオブジェクトを使い回す
    expect(a).to eq(b)  # ✅ パス
    expect(a).to be(b)  # ✅ パス
  end

  it "大きな整数の場合" do
    a = 1000000
    b = 1000000
    
    expect(a).to eq(b)      # ✅ パス(値が同じ)
    expect(a).not_to be(b)  # ✅ パス(異なるオブジェクト)
  end
end

配列の場合

RSpec.describe "配列の比較" do
  it "eqとbeの違い" do
    arr1 = [1, 2, 3]
    arr2 = [1, 2, 3]
    arr3 = arr1

    # 値は同じだが、異なるオブジェクト
    expect(arr1).to eq(arr2)     # ✅ パス(要素が同じ)
    expect(arr1).not_to be(arr2) # ✅ パス(異なるオブジェクト)

    # 同じオブジェクトを参照
    expect(arr3).to be(arr1)     # ✅ パス(同じオブジェクト)
  end
end

よくある使い分けパターン

1. 通常の値の比較にはeq

RSpec.describe User do
  it "ユーザー名が正しく設定される" do
    user = User.new(name: "太郎")
    expect(user.name).to eq("太郎")
  end
end

2. オブジェクトの同一性確認にはbe

RSpec.describe "ファクトリーパターン" do
  it "シングルトンオブジェクトが同じインスタンスを返す" do
    instance1 = Logger.instance
    instance2 = Logger.instance
    expect(instance1).to be(instance2)
  end
end

3. boolean値の場合

RSpec.describe "boolean値のテスト" do
  it "truthy/falsyな値のテスト" do
    # 真偽値そのものをテスト
    expect(user.active?).to be(true)
    expect(user.deleted?).to be(false)
    
    # 値の存在をテスト
    expect(user.email).to be_truthy
    expect(user.deleted_at).to be_falsy
  end
end

beの特殊な使い方

be_truthy / be_falsy

# 真偽値の判定
expect("hello").to be_truthy    # 空文字列以外は真
expect(nil).to be_falsy         # nilは偽
expect(0).to be_truthy          # 0は真(JavaScriptとは違う!)

be_nil

# nilかどうかの判定
expect(user.deleted_at).to be_nil
expect(user.deleted_at).not_to be_nil

be_present / be_blank(Rails環境)

# Railsの場合
expect(user.name).to be_present
expect(user.bio).to be_blank

実践的な例:モデルのテスト

RSpec.describe User do
  let(:user) { User.new(name: "太郎", email: "taro@example.com") }

  describe "#initialize" do
    it "正しい値で初期化される" do
      # 値の比較にはeq
      expect(user.name).to eq("太郎")
      expect(user.email).to eq("taro@example.com")
    end

    it "初期状態が正しく設定される" do
      # boolean値の確認にはbe
      expect(user.active?).to be(true)
      expect(user.admin?).to be(false)
      
      # nilの確認
      expect(user.deleted_at).to be_nil
    end
  end

  describe "#duplicate" do
    it "異なるオブジェクトが作成される" do
      duplicated_user = user.duplicate
      
      # 値は同じ
      expect(duplicated_user.name).to eq(user.name)
      expect(duplicated_user.email).to eq(user.email)
      
      # でも異なるオブジェクト
      expect(duplicated_user).not_to be(user)
    end
  end
end

まとめ

マッチャー 用途 Rubyのメソッド
eq 値の等価性 == expect(1 + 1).to eq(2)
be オブジェクトの同一性 equal? expect(obj1).to be(obj2)
be_truthy 真偽値判定 !!value expect("hello").to be_truthy
be_falsy 偽値判定 !value expect(nil).to be_falsy
be_nil nil判定 nil? expect(value).to be_nil

覚え方のコツ

  • 値を比較したいeqを使う
  • 同じオブジェクトか確認したいbeを使う
  • boolean値をテストしたいbe(true) / be(false)
  • 存在確認したいbe_truthy / be_falsy / be_nil

適切なマッチャーを選ぶことで、テストの意図が明確になり、保守性の高いテストコードが書けるようになります。最初は迷うかもしれませんが、この違いを意識することで、より良いテストが書けるようになるでしょう!

Discussion