Reputation: 25
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.
ATest_spec.rb
is test class. AwsUploader.s3upload
is called from letsUpload
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
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
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