如何对使用带有RSpec的REST API的方法进行单元测试?

时间:2016-02-16 12:54:33

标签: ruby rspec tdd automated-tests koala

我正在开发一个从外部REST API(来自Facebook,Twitter或Instagram等社交网络)获取数据的项目。

我不确定我所做的是对还是错所以我需要一些指导。我不知道当人们创建依赖于外部数据的应用程序(REST API或爬行数据)时,他们会使用它进行TDD。

我的问题是:我正在尝试对调用外部REST API的方法进行TDD测试。这是对还是错?

  • 如果没错,我该如何使用RSpec进行测试?有没有我可以阅读的指南或来源?
  • 如果错了,那该怎么办呢?如果我将API_VERSION更改为更高版本,我怎么知道逻辑仍然正常,所有必填字段仍然存在?

例如:

我有这样的代码:

API_VERSION = "v2.5"
FIELD_PAGE_GRAPH = %w(id name picture{url} likes cover is_community_page category link website has_added_app 
  talking_about_count username founded phone mission location is_published description can_post checkins company_overview
  general_info parking hours payment_options access_token
)

FIELD_STREAM_GRAPH = %w(id message story comments.summary(true) likes.summary(true).limit(500) from to link shares created_time
  updated_time type is_published attachments scheduled_publish_time application
)

def self.get_stat_facebook(page_id,access_token=nil)
  graph = Koala::Facebook::API.new(access_token)
  graph.get_objects(page_id.to_s,{:fields => FIELD_PAGE_GRAPH}, {:api_version => API_VERSION})
end

def self.get_feed_facebook(page_id,access_token=nil, options = {})
  options = options.with_indifferent_access
  retry_time = 0
  begin
    graph = Koala::Facebook::API.new(access_token)
    params = {:fields => FIELD_STREAM_GRAPH, :limit => 25}
    params.merge!({:since => options[:_since].to_i}) if options[:_since].present?
    params.merge!({:until => options[:_until].to_i}) if options[:_until].present?
    results = []
    loop do
      graph_response = graph.get_object(page_id.to_s+"/feed", params, {:api_version => API_VERSION})
      break if graph_response.blank?
      results = results+graph_response
      break if options[:_since].blank?
      params[:until] = graph_response.sort_by!{|result| result['created_time']}.first['created_time'].to_time.to_i-1
    end
  rescue Koala::Facebook::ServerError
    sleep 1
    retry_time += 1
    retry if retry_time <= 3
  end
  filter_owner_page(results, page_id)
end

然后我有一个像

这样的规范
require 'spec_helper'

RSpec.describe SocialNetwork do
  context ".get_stat_facebook" do
    it "when access token is expired"
    it "when access token is not expired"
    it "when page id is not exist"
    it "when page id is exist"
  end

  context ".get_feed_facebook" do
    it "when access token is expired"
    it "when access token is not expired"
    it "when page id is not exist"
    it "when page id is exist"
    it "data contain id field"
    it "data contain message field"
    it "data contain attachment field"
  end
end

4 个答案:

答案 0 :(得分:2)

是的,它适用于测试以获得外部服务,但您可以通过几种方式将其对测试套件的影响降至最低。

我会按如下方式测试此代码:

  • 注册Facebook test user
  • 使用测试用户编写RSpec功能规范或Cucumber方案,以测试在整个堆栈中使用Facebook的整个功能。使用the VCR gem记录Facebook的回复,以便远程调用不会减慢您的测试速度。
  • SocialNetwork编写RSpec规范(单元测试)。

    • 在每次拨打Facebook的一个或几个单元测试中,让他们使用测试用户点击Facebook,再次使用VCR来保持快速。或者,让他们中的一个或几个一直打到Facebook,以便你知道Facebook的API是否会发生变化。
    • SocialNetwork的其他规范中,只测试您已经测试过的调用变体的那些规范,找出考拉。

    很难准确地解释哪些测试应该打到Facebook以及哪些应该使用存根而不将它们放在我们面前。如果您需要更多建议,请查看它是如何发布的。

答案 1 :(得分:2)

TDD用于测试您的方法作为一个单元。来自外部的数据可以是mocked,因此您可以涵盖每个方案。像

这样的东西
graph = double()
allow(graph).to receive(:get_object).and_return(data)

-

我也会改变

context ".get_stat_facebook" do

代表

describe ".get_stat_facebook" do

并使用上下文来描述您要测试的方案。它将提高可读性。

更多:大方法难以测试,因此您可以将#get_feed_facebook分成小部分(如构建参数,循环等)以提高可测试性。

答案 2 :(得分:0)

听起来我想要实现的是功能/验收测试,而不是单元测试。我个人认为在单元测试中,你应该隔离你的单元(方法)并尝试注入所需的依赖项(mock)并评估函数的输出(期望和断言)。

在你的情况下,我认为你可以期待你使用的sdk方法,例如,你有以下方法:

def do_something_with_facebook
  @graph = Koala::Facebook::API.new(oauth_access_token)
end

在这种情况下,我会编写一个测试,检查您的方法是否如下所示调用Koala::Facebook::API

def test_method_calls_koalla
    grape = mock
    Koala::Facebook
      .expects(:new)
      .returns(grape)

    method = do_something_with_facebook
  end

它可能不是rspec语法,但我希望它能给你一些想法。

答案 3 :(得分:0)

你说,“我正在尝试对调用外部REST API的方法进行TDD测试。”对我来说,这是一个单元测试环(支付'测试方法'的短语)。 “这是对还是错?”,你问。绝对正确(IMO)。

我当前的项目广泛使用来自多个其他系统的外部API。我使用webmock。它给了我很多控制权,以确保请求格式正确(网址,查询,标题等),让我测试各种响应(成功,权限被拒绝,网络超时等)。而且,管理外部API版本也很容易。

对我来说,这是测试访问外部API的方法最直接,最低开销的方法。如果感兴趣的话,很高兴说出更多。