nolimits
nolimits

Reputation: 25

Test the size of array received is correct

I want to test if a function of a class is called with array of particular length.

Example in below I want to verify if function s3upload was called with array parameter where array size is 2.

Project/lib/First/version.rb
  module Documentz
    class AwsUploader
      def s3upload(event_id:nil, docs: nil)
        puts("uploded")
      end
    end
  end
Project/lib/First.rb
  module Exporter
    class AnExporter
      def letsUpload
        Documentz::Uploader::AwsUploader.new.s3upload( docs :[1,2])
      end
    end
  end
ATest_spec.rb
  it 'helps in mocking a class' do
    exp=Exporter::AnExporter.new
    exp.letsUpLoad
    allow_any_instance_of(Documentz::Uploader::AwsUploader).to receive(:s3upload).with( {:docs=>[1,2]})
    ## how to check if the array size (:docs)==2
  end

As you can notice in ATest_spec.rb I am able to test if the arguments are [1,2] but I actually want to verify that the size of array ( argument received) is actually 2.

Can you please advice how to do that?

Upvotes: 1

Views: 1179

Answers (2)

spickermann
spickermann

Reputation: 106882

Instead of allow_any_instance_of I would use the stub the new method and would return an instance_double on which I spy for the expected method call. To ensure that the argument has a specific structure use a custom matcher that can be as complex as needed, for example:

RSpec::Matchers.define :expected_data_structure do
  match { |actual| actual.is_a?(Hash)         &&
                   actual[:docs].is_a?(Array) && 
                   actual[:docs].size == 2    &&
                   actual[:docs].all?(Integer) 
  }
end

subject(:exporter) { Exporter::AnExporter.new }
let(:spy) { instance_double('Documentz::Uploader::AwsUploader') }

before do 
  allow(Documentz::Uploader::AwsUploader).to receive(:new).and_return(spy) 
end

it 'calls `s3upload` with the expected arguments' do
  exporter.letsUpLoad

  expect(spy).to have_received(:s3upload).with(expected_data_structure)
end

Read about custom matches in the RSpec docs.

Btw. in Ruby by convention method names are written in underscore and not in camelcase. Following that rule, your method should be named lets_up_load (or just upload) instead of letsUpLoad

Upvotes: 1

Amit Patel
Amit Patel

Reputation: 15985

Here you have mocked with a method to receive specific parameters, additionally, you need to return an array of the docs ids(assuming that's what your s3upload method would return)

allow_any_instance_of(Documentz::Uploader::AwsUploader).to receive(:s3upload).with( {:docs=>[1,2]}).and_return([1,2])
    
expect(exp.letsUpLoad.length).to eq 2

Upvotes: 0

Related Questions