Let block affects mocking in before block

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the testing category.

Last Updated: 2024-04-25

This is quite rspec specific so ignore if haven't worked in this environment. I had the following code:

class GenerateFinancialTransactionsReportService
  def build
    new(GetMonthlyAverageRatesService.build)
  end

  def new(get_monthly_average_rates_service)
     self.get_monthly_average_rates_service = get_monthly_average_rates_service
  end
end

describe GenerateFinancialTransactionsReportService do
  let!(:service) { GenerateFinancialTransactionsReportService.build }
  let(:get_monthly_average_rates_mock) {
  # A lambda can be used since it responds to #call as does my service
    ->(_) { { 'GBP' => 0.74 } }
  }

  before do
    allow(GenerateFinancialTransactionsReportService::GetMonthlyAverageRatesService).to receive(:build) {
      get_monthly_average_rates_mock
    }
  end

  it "works" do
     expect(service)...
  end
end

Unfortunately, my mock was not working. This was because the let! block called the build method before I had the chance to inject my mock.

The fix was to simply change let! to let and lazily evaluate service in the actual spec.