Busch
Busch

Reputation: 959

Rspec can't stub method for class

I have a class that puts some info into a database. Here is the method from the class I'm testing:

def load(configs)
  opts = { access_token:  configs['token'],
           api_endpoint:  configs['endpoint'],
           web_endpoint:  configs['site'],
           auto_paginate: configs['pagination']}

  client = Octokit::Client.new(opts)   

  repos = client.org_repos(configs['org'])
  repos.each do |r|
    Project.create(name: r.name)
  end

   rescue NoMethodError
  raise GitConfigError, 'put something here yet'
  end
end

I successfuly can test if it raises an error, however I don't know how to go about testing if the data is being put into the database correctly. I can't seem to find any resources on it either. Though, I did test the model in another spec. Any insight would be appreciated!

Upvotes: 0

Views: 956

Answers (3)

spickermann
spickermann

Reputation: 106882

I would stub both methods - the API call and the save into the database. The API call should be tested in the gem. And create is tested in Rails. You can assume that both methods work like described in the docs. Edge cases (like failing calls to creates cause of failing validations) should be tested separately.

I would write the spec like this:

context '#load' do
  let(:options) { token: 'foo', ... }
  let(:repos)   { [{ name: 'bar'}] }
  let(:client)  { instance_double(Octokit::Client, repos) }

  before do
    allow(Octokit::Client).to_receive(:new).and_return(client)
    allow(Project).to_return(:create).and_return(true)
  end

  it 'initializes the API client' do
    thing.load(options)

    expect(Octokit::Client).to have_received(:new).with(
      access_token: options[:token],
      # ...
    )
  end

  it 'stores records received from the API' do
    thing.load(options)

    expect(Project).to have_received(:create).with(name: 'baz')
  end
end  

Upvotes: 2

Sebastian
Sebastian

Reputation: 2786

In my opinion you can go with expect_any_instance_of(Octokit::Client).to receive(:org_repos).and_return([{name: "a"}, {name: "b"}]) You can find more information on rspec documentation

Upvotes: 0

pkurek
pkurek

Reputation: 606

I'm not sure if I understand you correctly but if by 'if the data is being processed correctly' you mean if it got saved in the database you could do something like

it "saves Project in db" do
   expect { subject.load([{name: "a"}, {name: "b"}]) }.to change(Project.count).from(0).to(2)
end

it "saves it with correct data" do
  subject.load([{name: "a"}, {name: "b"}])
  expect(Project.all.map(&:name)).to eql ["a", "b"]
end

or if the Octokit::Client.new(opts) is an external api you could use something like webmock or vcr to stub out api calls

it "calls external api and creates Project based on this data" do
  stub_request(:get, "http://api.example.com/cats").and_return([{name: "a"}, {name: "b" }])
  subject.load()
  expect(Project.all.map(&:name)).to eql ["a", "b"]
end

Upvotes: 0

Related Questions