测试 使用 Webmock 和 VCR 搭建测试,对调用第三方 API 库的支持

wootaw · July 21, 2015 · Last by yanhao replied at July 22, 2015 · 3403 hits

因为我们的接口中调用了第三方 API,最近在编写测试时遇到一些问题:

  • 对方不提供沙箱服务器
  • 对方的 API 有调用次数的限制
  • 有些服务只有接口文档,但还没有实现功能
  • 如果网络不好的时候,还会让测试跑起来龟速;有时候是网络原因,造成测试用例跑不过
  • 跑单元测试时却向真实 API 发送请求

直到发现 rest-client 里用到了Webmock

Webmock

首先在 Gemfile 中加入:

# Gemfile
group :test do
  gem 'webmock'
end

我开始时犯了一个错误,这么写:

# Gemfile
group :test, :development do
  gem 'rspec-rails'
  gem 'factory_girl_rails'
  gem 'simplecov'
  gem 'webmock'
end

结果导致在开发环境下,API 调用都不能用了:

WebMock::NetConnectNotAllowedError - Real HTTP connections are disabled. Unregistered request:

接着在 spec_helper.rb 里加入:

# spec/spec_helper.rb
require 'webmock/rspec'
WebMock.disable_net_connect!(allow_localhost: true)

现在可以按 API 文档的输入输出伪造一些 URL 了:

before(:each) do
  @valid_token = "blablabla"
  @valid_id = "blabla"
  stub_request(:post, "http://api.example.com/api/auth")
    .with(body: { token: @valid_token })
    .to_return(status: 201, body: { id: @valid_id, token: @valid_token }.to_json)

  @invalid_token = "invalidblablabla"
  stub_request(:post, "http://api.example.com/api/auth")
    .with(body: { token: @invalid_token })
    .to_return(status: 401)
end

但是这样写,在每个调用了第三方 API 的测试里,开头都得定义一堆这样的东西,乱乱的。又发现一个好东西 VCR

VCR

这东西有个最大的好处就是可以让我们按第三方 API 文档的说明,集中的定义好所有伪造 URL

首先在 spec_helper.rb 里加入:

# spec/spec_helper.rb
RSpec.configure do |config|
  config.before(:each) do
    stub_request(:any, /api.example.com/).to_rack(BlaApi)
  end
end

然后在 spec/support/下创建一个:

# spec/support/bla_api.rb
class BlaApi < Grape::API   # 我们用的Grape
  prefix :api
  format :json

  namespace :auth do

    post do
      case params[:token]
      when "blablabla" # valid token
        { id: "blabla", token: "blablabla" }
      when "invalidblablabla" # invalid token
        error!({ "error" => "bla bla bla" }, 401)
      else
        error!({ "error" => "bla bla bla" }, 401)
      end
    end

  end
end

现在就可以按照 API 文档尽情伪造 URL 了

后记

还有一些想法,没有实现,有兴趣的大虾们可以就此展开

  • 对于返回数据量大的 API,我们可以把数据存到一个 yml 文件中,在 BlaApi 里读出返回,这样就可以灵活配置修改返回的数据了
  • 是不是可以在第一次调用时请求真实的 API,然后把数据缓存起来,之后的请求就可以一直使用被缓存的数据
  • 有些 API 会回调请求调用者的服务器(调用者可能会对数据库做修改),再根据调用者的返回组装数据,生成他们的 API 返回。这样的 API 怎么测试

不错!

可以试试 hurley

关于测试 https://github.com/lostisland/hurley#testing 关于缓存 https://github.com/plataformatec/hurley-http-cache

关于你说的第三点,这个是个伪命题,测试只需要关注 request 和 response,你需要根据情况返回特定的 response

最近正对这方面苦恼呢,赶紧学习一下。

是不是可以在第一次调用时请求真实的 API,然后把数据缓存起来,之后的请求就可以一直使用被缓存的数据

VCR 默认的工作方式就是这样的,也许你只需要删掉这行:WebMock.disable_net_connect!(allow_localhost: true).

You need to Sign in before reply, if you don't have an account, please Sign up first.