LoginSignup
0
0

More than 5 years have passed since last update.

Ruby|RSpecでメソッド呼び出しのテスト(ブロック付き)

Posted at

いつものように「これ、誰がつかうん?」という小ネタです。

たまーにRSpecでメソッドってちゃんと呼び出されてるよね?というテストを書くと思います。withを使うと引数に狙った値が渡っているかを検証できますが、ブロック付きはどうするか調べたのでそのメモです。

先に言ってしまうと検証は「&手続きオブジェクト」の場合のみ出来ます。

前段階

検証に使うプログラムはDeckクラスを利用します。これは何枚かのカードを持っていてシャッフルしたり偶数と奇数を分けてくれます。今回の検証はDeck#split_even_numbersEnumerable#partitionにブロックを渡していますが、それをRSpecでテストする方法です。

本来であればメソッドを呼び出した結果を検証すべきですので、メソッド呼び出しのみのテストはいいと言ってはいません。用法用量を守るのはお兄さんとのお約束だぞ:wink:

class Deck
  def initialize(cards)
    @cards = cards
  end

  def shuffle
    @cards.shuffle
  end

  def split_even_numbers
    @cards.partition { |card| card.even? }
  end

  def split_odd_numbers
    @cards.partition(&:odd?)
  end
end

RSpec

ブロックの検証

withにブロックを指定すると{ |card| card.even? }を受け取ることができるようです。&blockとしているのでProcクラスのオブジェクトになっています。

Procクラスのオブジェクトをつくって比較すればいいか!と思っていたのですが、メソッドに渡してるブロックとは異なるようでテストはうまくいきませんでした:sweat_smile:

describe Deck do
  describe '#split_even_numbers' do
    let(:deck) { Deck.new(cards) }
    let(:cards) { [5, 4, 3, 2, 1] }

    it do
      expect(cards).to receive(:partition).with(no_args) do |&block|
        # この検証はうまくいかない
        expect(block).to eq(Proc.new{ |card| card.even? })
      end
      deck.split_even_numbers
    end
  end
end

&手続きオブジェクト

「&手続きオブジェクト」といっていますが検証したいProcクラスのオブジェクトとテストでの期待値が同じオブジェクトであれば今回のやりたいことは実現することが出来ます。

:odd?.to_procは常に同じオブジェクトを返すので検証で利用して期待した結果を得ることが出来ます。

describe Deck do
  describe '#split_odd_numbers' do
    let(:deck) { Deck.new(cards) }
    let(:cards) { [5, 4, 3, 2, 1] }

    it do
      expect(cards).to receive(:partition).with(no_args) do |&block|
        expect(block).to eq(:odd?.to_proc)
      end
      deck.split_odd_numbers
    end
  end
end
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