Testing 一个测试 JSON API 时用来对比 JSON 内容的 helper,以及请教是否有更优雅的写法

cn_boris · 2015年04月21日 · 最后由 cn_boris 回复于 2015年04月23日 · 2037 次阅读

业务需求

在测试 json api 时,测试返回的json是否与预期的一致。

最初的解决方案 

使用了一个叫做 assert_json 的GEM。但感觉过于繁琐,特别是在测试用例多的时候。

现时的解决方案

手写了几个helper

def response_json
   JSON.parse(response.body)
 end

 # data_map could look like {uid: :id,last_name: :last_name,full_name: '"#{exp['last_name']}#{exp['first_name']}"'}
 def assert_json_equal(exp, data_map=nil, act=response_json)
   act=JSON.parse(act) if act.is_a?(String)
   data_map || (data_map=act.keys)
   (data_map = Hash[data_map.map { |v| [v, v.to_sym] }]) if data_map.is_a?(Array) # convert array to hash (key == value)
   data_map.each do |k, v|
     k=k.to_s
     if v.is_a?(Symbol)
       assert_equal exp[v], act[k]
     elsif v.is_a?(String)
       assert_equal eval(v), act[k]
     elsif v.is_a?(Hash) # support insets
       assert_json_equal(exp,v,act[k])
     else
       false
     end
   end
 end

使用示例

假设我们有这样1个model

User (id,last_name,first_name,password,updated_at,created_at)

当 json 返回值为 User.first.to_json 时,直接使用 assert_json_equal User.first 即可,而无需指定data_map。

当 json 只返回 {"id":1,"last_name":'Jobs'} 时,则需使用数组作为data_map,形如 assert_json_equal User.first,[:id,:last_name]

而当 json 返回的数据结果较复杂时,则需要使用hash作为data_map,形如:

 // json 返回结果
{"uid":1,full_name: 'Steve Jobs',password:'123'}
# 验证json返回
@data_map={
  uid: :id,
  full_name: '"#{exp.first_name} #{exp.last_name}"',
  password: :password
}

 assert_json_equal User.first,@data_map

问题

总觉得这样的实现似乎有点怪怪的,以及是否有更优雅的写法?

Ruby新手一枚,还望各位大牛不吝赐教。

共收到 8 条回复

所以就是说…不能嵌套? = =

顺序固定的话 to_s 对比字符串(JSON 本身就是字符串)。

assert_equal {"id" => 1, "name" => "lolychee"}, User.first.slice(:id, :name)

和我一样的测试,同问

一个个attributes比较实际上测的是schema,你不需要每个测试都测schema啊。

比如你要测某个action是否返回特定用户,查看id就够了,这样测试也很容易读。测修改用户名的action, id和用户名就可以了。

#2楼 @rei 直接對比字符串的話,似乎沒辦法捕獲到具體是哪個字段出現了錯誤?

#5楼 @billy 主要和我們的業務需求有關係,不同 action 返回的 schema 並不一致。且有時候可能會需要測試某個 attributes 的值是否正確,因爲返回的 json 並不總是和 model.to_json 完全相同。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册