17

I'm creating an API that accepts JSON data and I want to provide testing data for it.

Is there anything similar to factories for JSON data? I would like to have the same data available in an object and in JSON, so that I can check if import works as I intended.

JSON has strictly defined structure so I can't call FactoryGirl(:record).to_json.

5 Answers 5

32

In cases like this, I'll create fixture files for the JSON I want to import. Something like this can work:

json = JSON.parse(File.read("fixtures/valid_customer.json"))
customer = ImportsData.import(json)
customer.name.should eq(json["customer"]["name"])

I haven't seen something where you could use FactoryGirl to set attributes, then get it into JSON and import it. You'd likely need to create a mapper that will take your Customer object and render it in JSON, then import it.

Sign up to request clarification or add additional context in comments.

Comments

21

Following Jesse's advice, in Rails 5 now you could use file_fixture (docs)

I just use a little helper for reading my json fixtures:

def json_data(filename:)
  file_content = file_fixture("#{filename}.json").read
  JSON.parse(file_content, symbolize_names: true)
end

3 Comments

Where are you putting this helper? rails_spec.rb?
@DanielCosta I have a module helpers at spec/support/helpers.rb. Then in the rails_helper I include them with config.include Helpers
This is a very nice convenience, you can also just inline it in your specs as needed, very simple
5

Actually you can do the following with factorygirl.

factory :json_data, class: OpenStruct do 
   //fields
end

FactoryGirl.create(:json_data).marshal_dump.to_json

Comments

1

Here's something that works well for me. I want to create deeply nested structures without specifying individual factories for each nesting. My usecase is stubbing external apis with webmock. Fixtures don't cut it for me since I need to stub in a variety of different data.

Define the following base factory and support code:

FactoryBot.define do
  factory :json, class: Hash do
    # Don't try to persist the object
    skip_create
    # Grab only what is defined in the json block
    initialize_with { attributes[:json].to_json }
  end
end

I can then define the actual factory like this:

FactoryBot.define do
  factory :json_response, parent: :json do
    # You can define any attributes you want here
    # to use as parameters in the json block
    ids { [] }
    
    # The result of this block is what FactoryBot will return
    json do
      ids.map do |id|
        {
          score: 90,
          data: {
            id: id,
          },
        }
      end
    end
  end
end

Finally you can use it like this:

FactoryBot.build(:json_response, ids: [1,2])
=> "[{\"score\":90,\"data\":{\"id\":1}},{\"score\":90,\"data\":{\"id\":2}}]"

Comments

0

Sometime ago we implemented FactoryJSON gem that addresses this issue. It worked quite well for us so far. Readme file covers possible use cases.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.