Search code examples
ruby-on-railsarraysrubyruby-on-rails-4rspec

RSpec expect to receive method with array but order does not matter


Lets say I have method #sum which takes an array and calculates sum of all elements. I'm stubbing it:

  before do
    expect(calculation_service).to receive(:sum?).with([1, 2, 3]) { 6 }
  end

unfortunately my test suit passes array in random order. Because of that error is raised:

 Failure/Error: subject { do_crazy_stuff! }
   #<InstanceDouble() (CalculationService)> received :sum? with unexpected arguments
     expected: ([1, 2, 3])
          got: ([3, 2, 1])

Is it possible to stub method call ignoring order of an array elements? array_including(1, 2, 3) does not ensure about array size, so it probably is not the best solution here


Solution

  • You can pass any RSpec matcher to with, and contain_exactly(1, 2, 3) does exactly what you want, so you can pass that to with:

    expect(calculation_service).to receive(:sum?).with(contain_exactly(1, 2, 3)) { 6 }
    

    However, "with contain exactly 1, 2, 3" doesn't read very well (and the failure message will be similarly grammatically awkward), so RSpec 3 provides aliases that solve both problems. In this case, you can use a_collection_containing_exactly:

    expect(calculation_service).to receive(:sum?).with(
      a_collection_containing_exactly(1, 2, 3)
    ) { 6 }