今年的 QCon 上, 七牛的人介绍了下他们的接口测试体系. 我发现碰巧和我们公司做的一样.
他说他的测试体系是用 go 实现的, 并且说思想是来自于...
不过类似的测试框架 ruby 早就有了. 今天就给大家分享下.
开源项目地址 https://github.com/okitan/capybara-json
样例代码如下
require 'capybara/json'
include Capybara::Json
Capybara.current_driver = :httpclient_json
Capybara.app_host = 'http://example.com'
post '/', { "this is" => "json" } # POST 'http://example.com/'
json #=> parsed json response
raw_json #=> raw response body
get '/errors/400'
status_code #=> 400
get! '/errors' #=> raise Capybara::Json::Error
get '/errors', {}, { 'header' => '' } # set request headers
response_headers #=> get response headers
是不是非常的简单. 我们公司的接口测试就是基于这个小框架做的.
capybara 是什么那. 是一个新的测试框架.他也是 Rails 的作者极力推崇的一个框架. 他的功能太强大了, 以至于我不能在此介绍它.
大家可以自己去 github 上看看.
我在公司开发了一个接口测试工具. 这个工具的实现思路如下.
利用 fiddler 或者其他的反向代理工具, 截获各个模块之间的请求. 然后保存下来.比如 fiddler 就有个导出为 HAR 格式的功能.
然后解析这个 HAR, 发送之前录制好的请求, 然后拿系统实际返回的结果与之前 HAR 中保存的结果进行比对.
为了统计结果, 所以使用了 xunit 框架. 因为这是数据驱动的方式, 不是硬编码. 所以需要用到一个单测的 hack 技巧. 动态生成测试用例.
#coding: utf-8
require 'rubygems'
require 'json'
require 'pp'
require 'minitest'
require 'minitest/autorun'
require 'capybara/json'
include Capybara::Json
#把返回的json解析为结构, 去掉具体的数字. 比如"xxx"会被解析为"String"
def to_struct(h)
if h.class==Hash
new=h.clone
h.map do |k,v|
new[k]=to_struct(v)
end
end
if h.class==Array
new=[]
h.each do |x|
new << to_struct(x)
end
end
if h.class!=Array && h.class!=Hash
new=h.class.to_s
end
new
end
DynamicTest = Struct.new :name, :expected, :actual
DYNAMIC_TESTS = []
Capybara.current_driver = :httpclient_json
#Capybara.app_host = 'http://10.128.6.44:18080'
host="oneapm.com"
index=0
Dir["data/*.har"].each do |data_file|
content=IO.read(data_file, :encoding=>"UTF-8")
obj = JSON.parse(content[1..-1])
1.times do |i|
now=Time.now.strftime("%s").to_i
obj['log']['entries'].each do |entry|
index+=1
method=""
entry['request']['url'].sub!("10.128.6.44:18080", host)
begin
now=Time.now.strftime("%s").to_i-60
if method=='metric_data'
data[1]=(now-60)
data[2]=now
end
post entry['request']['url'], data.to_json
testcase_name="test_#{data_file.gsub('/', '_')}_#{method}_#{index.to_s}"
p "create testcase #{testcase_name}"
#动态生成值对比的单测用例
DYNAMIC_TESTS << DynamicTest.new(testcase_name+"_diff_value", raw_json, entry['response']['content']['text'])
begin
expect_s=to_struct(JSON.parse(entry['response']['content']['text']))
rescue
expect_s="json parse error"
end
begin
actual_s=to_struct(JSON.parse(raw_json))
rescue
actual_s="json parse error"
end
#动态生成结构对比的单测用例
DYNAMIC_TESTS << DynamicTest.new(testcase_name+"_diff_struct", expect_s, actual_s)
rescue
p "exception"
p entry['request']['url']
end
end
sleep 1
end
end
#动态生成单测方法
class HARDiff < MiniTest::Test
class << self
def create_method(t)
define_method(t.name) do
assert_equal t.expected, t.actual
end
end
end
end
DYNAMIC_TESTS.each do |t|
HARDiff.create_method t
end
代码经过裁剪, 仅供参考
代码非常的少, 主要是特点如下
使用场景是
提前录制好系统的交互. 然后新版本环境上线. 使用录制好的数据回放请求并验证接口的变更情况. 这种方式简单粗暴.但是可以保证接口的稳定.