Search code examples
ruby-on-railsrubyrspecmockingrspec-mocks

How to check that a method has called another method with RSpec


I have the following code structure (abbreviated for length):

module Uploader
  def self.execute(folder)
    report_record = Reporting::GenerateReports.call
    establish_api_connection
    upload_file(report_record.first_report, folder)
  end

  def self.upload_file(report, folder)
    upload_content(report.download, "/#{folder}/#{report.filename}")
  end

  def self.upload_content(content, path)
    ...
  end
end

At the moment, I can spec calling the execute method in RSpec to ensure that upload_file gets called. However, how do I mock to check that upload_file calls upload_content?


Solution

  • Remember that expect and allow both stub the method call - they prevent it from actually running. If you want to check that one method was called, and also make sure that method calls another method, you need to use .and_call_original.

    # Some setup
    folder = "some fake folder" # not sure the data type
    report = Reporting::GenerateReports.call
    allow(Reporting::GenerateReports).to receive(:call).and_return(stub_report)
    
    # Expectations
    expect(Uploader).to receive(:execute).with(some_folder).and_call_original
    expect(Uploader).to receive(:upload_file).with(report, folder)
    

    That allow(Reporting::GenerateReports) line is needed because the report_record variable is defined inside your execute method (cannot pass in a custom value from the tests via dependency injection). To ensure that the correct argument is passed to upload_file, it therefore needs to be stubbed out.