thoughtbot / factory_bot

A library for setting up Ruby objects as test data.
https://thoughtbot.com
MIT License
7.91k stars 2.6k forks source link

Allow factories to use RSpec example methods such as `double` #1252

Open danielpclark opened 5 years ago

danielpclark commented 5 years ago

This can either be an improvement or something to add to the documentation as suggested by Daniel J Colson on Twitter.

The simple feature is to, at least, use RSpec's double within a factory's initialize_with.

How

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods

  config.before(:suite) do
    FactoryBot.find_definitions
    FactoryBot::Evaluator.include RSpec::Mocks::ExampleMethods
  end
end

Why?

I've written a test suite for a third party API and I need to mock the response. For external requests I'm using Webmock with VCR but that has no bearing on this particular issue. The issue is to test my own code before any external API ever needs to be hit. Here's a sample:

FactoryBot.define do
  Response = Trav3::Response
  factory :response do
    initialize_with do
      dbl = double
      allow(dbl).to receive(:body).and_return( { a: :b, c: :d }.to_json )
      new(build(:travis), dbl)
    end
  end
end

Now I can use the nice and readable format of double within initialize_with and don't have to resort to:

dbl = Object.new
dbl.define_singleton_method(:body) { { a: :b, c: :d }.to_json }
composerinteralia commented 5 years ago

I came across https://github.com/thoughtbot/factory_bot/issues/703, which seems somewhat related.

danielpclark commented 5 years ago

Thanks @composerinteralia . I find it interesting that @printercu used the class FactoryGirl::SyntaxRunner to include on. I'm not sure if one is better than the other.

The way I went about solving where, and what, to include the desired methods was first in a rspec test I used byebug to find method(:double).owner to get RSpec::Mocks::ExampleMethods and then again within initialize_with within a factory I used byebug to get the class name for which to include the module in FactoryBot::Evaluator. And afterwards it just worked.

It is nice to know that there was an answer out there to find already. But when I searched online I did not come across any answers. It's likely I didn't have the right search words/terms to get to it. That's one reason why I think this would really be helpful to have in the official docs.

composerinteralia commented 5 years ago

I haven't had time to work on this yet, but I also spotted another issue that might be related: https://github.com/thoughtbot/factory_bot/issues/564.

pirj commented 3 years ago

Wondering if this will work for you:

FactoryBot.define do
  Response = Trav3::Response
  factory :response do
    body { { a: :b, c: :d }.to_json }
  end
end