【问题标题】:RSpec Mock - class does not implement the instance method: jql. Perhaps you meant to use `class_double` instead?RSpec Mock - 类不实现实例方法:jql。也许您打算使用 `class_double` 代替?
【发布时间】:2020-02-18 11:28:26
【问题描述】:

我想模拟使用Jira-Ruby gem with jql lib的方法

def call
  client = JIRA::Client.new(options)
  client.Issue.jql(
    "project = #{project_key} AND
    status != Done AND
    status != Closed AND
    status != Cancelled AND
    status != Followup",
    query_options
  )
end

我的模拟:

  let(:jql_options) do
    [
      "project = TSW-123 AND
      status != Done AND
      status != Closed AND
      status != Cancelled AND
      status != Followup",
      query_options
    ]
  end
  let(:query_options) do
    {
      start_at: 0,
      max_results: 1000
    }
  end
  let(:jira_client) { instance_double(JIRA::Client) }
  let(:issue) { instance_double(JIRA::Resource::Issue) }
  let(:issue_factory) { instance_double(JIRA::Resource::Issue) }

  before do
    allow(JIRA::Client).to receive(:new).with(options).and_return(jira_client)
    allow(jira_client).to receive(:Issue).and_return(issue_factory)
    allow(issue_factory).to receive(:jql).with(*jql_options).and_return(issue)
  end

  it 'connect to the project' do
    expect(subject.call).to eq(project)
  end

我收到一个错误:

JIRA::Resource::Issue 类没有实现实例方法:jql。也许您打算改用class_double

【问题讨论】:

  • 正如错误所说,jql 方法是一个类方法(在issue_factory 定义中定义为self.jql) so, it should work if you change instance_double 到class_double。另外,我想你可以说allow(JIRA::Resource::Issue). to receive...
  • “另外,我认为你可以”我很确定这是必需的,否则模拟将只是这个本地 issue_factory

标签: ruby rspec


【解决方案1】:

一些事情:

  • 您正在对静态值而不是对象使用模拟语法。我在这里对您的其他问题的回答应该会有所帮助:https://stackoverflow.com/a/60404227/4024628 IMO,在这里使用 instance_double 很好,因为您正在模拟实例,但如果您要调用模拟对象的方法,您通常需要在 instance_double 声明中定义它们的响应(如我的链接评论中所述)。
  • 小心测试模拟行为;您只需要测试客户端对象是使用某些选项创建的,并且 jql 是使用特定参数调用的(意思是,确保您正在验证代码的行为以防止破坏性更改——而不是 gem 的行为)。
  • 您的规范正在测试call 返回project,但您没有在任何地方定义或模拟它?
  • 您还将issue_factoryissue 定义为同一类的instance_doubles,这与您正在使用的类的文档不一致(错字?)。

这样的事情可能就足够了:

# You should always name your subject if you are calling methods on it
subject(:instance) { described_class.new }

let(:client)        { instance_double(JIRA::Client)
let(:issue_factory) { instance_double(JIRA::Resource::IssueFactory) }
# This likely needs to be an OpenStruct instead since docu says it returns an obj
let(:project)       { instance_double(JIRA::Resource::Project) }

before do 
  allow(client).to receive(:new).with(options)  { client }
  allow(client).to receive(:Issue) { issue_factory }
  allow(issue_factory).to receive(:jql).with(*jql_options) { project }
end

it 'creates client with correct options' do 
  expect(client).to receive(:new).with(options) 
  instance.call
end

it 'calls #jql with correct options' do
  expect(issue_factory).to receive(:jql).with(*jql_options)
  instance.call
end

it { expect(instance.call).to eq(project) }

【讨论】:

    猜你喜欢
    • 2016-02-22
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多