1

我已经对该主题进行了一些谷歌搜索,但我仍然感到困惑。

我正在使用 Zendesk API Ruby 客户端构建自定义帮助页面,并且我正处于需要测试ZendeskAPI::Ticket资源创建的阶段。以下代码位于 spec/features 目录中。它使用有效值填写表单并将表单提交给#create操作。相当标准,简单的东西。

require 'spec_helper'

feature 'ticket creation' do
  scenario 'user creates new ticket' do
    visit root_path

    fill_in 'Name', with: 'Billybob Joe'
    fill_in 'Email', with: 'joe@test.com'
    fill_in 'Subject', with: 'Aw, goshdarnit!'
    fill_in 'Issue', with: 'My computer spontaneously blew up!'
    click_button 'Create Ticket'

    expect(page).to have_content('Ticket details')
  end
end

这是门票控制器的相关部分。该ticket_valid?方法为选项哈希提供最少的验证,并且clientZendeskAPI::Client.

def create
  options = { subject: params[:subject], comment: { value: params[:issue] }, 
              requester: params[:email], priority: 'normal' }
  if ticket_valid? options
    flash[:success] = 'Ticket created.'
    @ticket = ZendeskAPI::Ticket.create(client, options)
    redirect_to ticket_path(@ticket.id)
  else
    flash[:error] = 'Something went wrong. Try again.'
    redirect_to root_url
  end
end

问题是,每当我运行测试时,都会在 Zendesk 后端创建一个实际的票证,稍后当我只想测试是否成功提交表单而不实际创建票证时,我必须手动删除它。

所以我的问题是,如何在运行测试时在 Zendesk 后端不创建实际票证的情况下测试票证创建表单?

由于我的谷歌搜索,我一直在阅读的文章和博客含糊地提到了使用 RackTest,而其他人则建议根本不使用 Capybara 来做这类事情,这让我更加困惑。我对 RSpec 还是比较陌生,甚至在处理使用 API 构建 Rails 应用程序方面还是比较新的,所以一个清晰的解释会很棒。

提前致谢!!你真棒。

4

2 回答 2

1

一种方法是将您的 ZenDesk 接口抽象到您自己的类中,然后在您的测试中模拟它。

例如,您可以创建一个接口类:

class ZendeskGateway

  def create_ticket(client, options)
    ZendeskAPI::Ticket.create(client, options)
  end

end

然后,在您的代码中,您将控制器中 Zendesk API 的使用替换为您的接口类:

class TicketsController < ApplicationController

  attr_accessor :zendesk_gateway

  after_initialize :init

  def init
    @zendesk_gateway = ZendeskGateway.new
  end 

  def create
    options = { subject: params[:subject], comment: { value: params[:issue] }, 
                  requester: params[:email], priority: 'normal' }
    if ticket_valid? options
      flash[:success] = 'Ticket created.'

      @ticket = @zendesk_gateway.create_ticket(client, options)

      redirect_to ticket_path(@ticket.id)
    else
      flash[:error] = 'Something went wrong. Try again.'
      redirect_to root_url
    end

  end

end

现在它已被抽象化,您可以在测试期间使用模拟框架(如mocha)来存根该方法,以便它实际上不会调用 Zendesk:

zendesk_ticket = ZendeskAPI::Ticket.new(client, :id => 1, :priority => "urgent")

@controller.zendesk_gateway.expects(:create_ticket).returns(zendesk_ticket)

这是一个非常快速/肮脏的例子。但希望你能看到总体思路。

于 2013-08-11T00:17:21.540 回答
0

如果您不想调用 Zendesk,则必须创建一个“测试替身”而不是实际调用。RSpec 附带的测试双重功能在https://github.com/rspec/rspec-mocks中进行了最低限度的描述,但在博客和书籍中进行了更全面的介绍。

同时发布的答案讨论了创建一个单独的类,但似乎仍然涉及创建 Zendesk 票证。您实际上不需要单独的类,也根本不需要创建任何 ZendeskAPI 对象。相反,您将存根ZendeskAPI::Ticket#create返回一个测试替身,而替身又需要提供其余测试所需的任何 Zendesk 票证方法,其中至少包括id.

Capybara 的使用确实是次要问题,指的是您如何进行测试。但请注意,您的测试当前需要呈现工单页面并检查该页面的内容。如果您想“仅”测试您的控制器,那么您可以/应该只测试它是否进行了正确的调用(例如 to ZendeskAPI::Ticket)并重定向到适当的页面。此外,如果你这样做,你在测试替身中模拟的东西就会少得多。

于 2013-08-11T00:17:36.187 回答