Rspec 无法为 class 存根方法

Rspec can't stub method for class

我有一个 class 可以将一些信息存入数据库。这是我正在测试的 class 中的方法:

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

我可以成功地测试它是否会引发错误,但是我不知道如何测试数据是否被正确地放入数据库中。我似乎也找不到任何资源。不过,我确实在另一个规范中测试了该模型。任何见解将不胜感激!

我不确定我是否理解正确但如果 'if the data is being processed correctly' 你的意思是如果它保存在数据库中你可以做类似

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

或者如果 Octokit::Client.new(opts) 是外部 api 你可以使用类似 webmock 或 vcr 的东西来停止 api 调用

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

我认为你可以选择 expect_any_instance_of(Octokit::Client).to receive(:org_repos).and_return([{name: "a"}, {name: "b"}]) 您可以在 rspec documentation

上找到更多信息

我会存根这两种方法 - API 调用和保存到数据库中。 API 调用应在 gem 中进行测试。并且 create 在 Rails 中进行了测试。您可以假设这两种方法都像文档中描述的那样工作。应单独测试极端情况(如调用失败导致验证失败)。

我会这样写规范:

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