jedi
jedi

Reputation: 2200

How to properly mock objects in RSpec?

I have a simple class, which generates a download URL to a file stored on S3 and I need to write a unit test to test this class. So far I've had no luck.

class S3DownloadUrlGenerator
  def initialize(filename)
    @filename = filename
  end

  def presigned_url
    signer = Aws::S3::Presigner.new(client: s3)
    signer.presigned_url(
      :get_object,
      bucket: "my-bucket",
      key: filename,
      response_content_disposition: "attachment",
    )
  end

  private

  def s3
    @s3 ||= Aws::S3::Client.new(
      region: "my-region,
      http_open_timeout: 5,
      http_read_timeout: 25,
    )
  end

  attr_reader :filename
end

I want to test if calling #presigned_url on an instance of S3DownloadUrlGenerator returns a URL. This is my test:

describe S3DownloadUrlGenerator do
  before do
    allow(Aws::S3::Client).to receive(:new) { s3_client }
  end
  let(:s3_client) { spy("s3 client") }
  let(:presigner) { spy("s3 presigner") }

  it "generates download URL for a file" do
    expect(Aws::S3::Presigner).to receive(:new).with(client: s3_client).and_return(presigner)
    expect(presigner).to receive(:presigned_url).with(
      :get_object,
      bucket: "my-test-bucket",
      key: "test_file.txt",
      response_content_disposition: "attachment",
    ).and_return("https://www.example.com")
    expect(described_class.new("Test_file.txt").presigned_url).to eq("https://www.example.com")
  end
end

but I get an error:

Failure/Error: expect(described_class.new("Test_file.txt").presigned_url).to eq("https://www.example.com")

       expected: "https://www.example.com"
            got: #<Double "s3 presigner">

       (compared using ==)

I am bit new to this and I would like to learn how to properly test such cases. Thank you very much for the help.

Upvotes: 0

Views: 1227

Answers (1)

rahul mishra
rahul mishra

Reputation: 1470

bucket and key parameters differ in actual calling and mocking. Use below code it works:

describe S3DownloadUrlGenerator do
  before do
    allow(Aws::S3::Client).to receive(:new) { s3_client }
  end
  let(:s3_client) { spy("s3 client") }
  let(:presigner) { spy("s3 presigner") }
  it "generates download URL for a file" do
    expect(Aws::S3::Presigner).to receive(:new).with(client: s3_client).and_return(presigner)
    expect(presigner).to receive(:presigned_url).with(
      :get_object,
      bucket: "my-bucket",
      key: "Test_file.txt",
      response_content_disposition: "attachment",
    ).and_return("https://www.example.com")
    expect(described_class.new("Test_file.txt").presigned_url).to eq("https://www.example.com")
  end
end

Upvotes: 3

Related Questions