rspec(4) - request

没有测试的代码就是耍流氓

  1. rspec(1) - summary
  2. specs(2) - model
  3. specs(3) - controller
  4. specs(4) - request
  5. specs(5) - mock
  6. [specs(6) - mailer]
  7. [specs(7) - view]
  8. [specs(8) - routing]
  9. [specs(9) - helper]
  10. [specs(10) - factory-girl]
  11. [specs(11) - fake other gems]
  12. [specs(12) - sidekiq]
  13. [specs(13) - db migration]
  14. [specs(14) - timecop]
  15. [specs(15) - jenkins]

in general, we want to test our api, what should we do in rspec?

require "rails_helper"

RSpec.describe "User management", :type => :request do

  it "creates a User" do
    headers = {
      "ACCEPT" => "application/json",     # This is what Rails 4 accepts
      "HTTP_ACCEPT" => "application/json" # This is what Rails 3 accepts
    }
    lamda do
      post "/users", { user: {name: "zql"} }, headers
    end.should change(User, :count).by(1)

    expect(response.content_type).to eq("application/json")
    expect(response).to have_http_status(:created)

    user = User.last
    user.name.should eq "zql"
    # or 
    expect(user.name).to eq "zql"
  end

end

webmock

what should we do if we want to test external request?
a nice gem you can use, webmock
just like this(examples from webmock github):

stub_request(:post, "www.example.com").
  with(body: "abc", headers: { 'Content-Length' => 3 })
RestClient.post('www.example.com', "data[a]=1&data[b]=five",
  content_type: 'application/x-www-form-urlencoded')    # ===> Success

RestClient.post('www.example.com', '{"data":{"a":"1","b":"five"}}',
  content_type: 'application/json')    # ===> Success

RestClient.post('www.example.com', '<data a="1" b="five" />',
  content_type: 'application/xml')    # ===> Success

it's so easy to do this, right?

and more.

  • match body
stub_request(:post, "www.example.com").
  with(body: hash_including({data: {a: '1', b: 'five'}}))

RestClient.post('www.example.com', "data[a]=1&data[b]=five&x=1",
:content_type => 'application/x-www-form-urlencoded')    # ===> Success
  • match headers
stub_request(:any, "www.example.com").
  with(headers:{ 'Header-Name' => 'Header-Value' })

uri = URI.parse('http://www.example.com/')
req = Net::HTTP::Post.new(uri.path)
req['Header-Name'] = 'Header-Value'

res = Net::HTTP.start(uri.host, uri.port) do |http|
  http.request(req, 'abc')
end    # ===> Success
  • auth required
stub_request(:get, "www.example.com").with(basic_auth: ['user', 'pass'])
# or
# stub_request(:get, "www.example.com").
#   with(headers: {'Authorization' => "Basic #{ Base64.strict_encode64('user:pass').chomp}"})

Net::HTTP.start('www.example.com') do |http|
  req = Net::HTTP::Get.new('/')
  req.basic_auth 'user', 'pass'
  http.request(req)
end    # ===> Success

please visit webmock if you wnat to more advange usage

but if we use gems like faraday or rest-client, so what should we should in rspec?
yeah, we want to mock a api request like mocking a model. here we go.

faraday

firstly, you should have a look at faraday testing, here are some example provided:

conn = Faraday::Adapter::Test::Stubs.new do |stub|
     stub.get('/ping') { |env| [200, {}, 'hello world!'] }
     stub.get('/other_url') { |env| [ 200, {}, 'hello, it's me, another test case' ]}
end
# or
cnnn = Faraday.new do |builder|
  builder.adapter :test, stubs do |stub|
    stub.get('/test') { |env| [ 200, {}, 'test case' ]}
  end
end

test request result

resp = test.get '/ping'
resp.status.should eq 200
resp.body.should eq 'hello world!'

resp = test.get '/other_url'
resp.status.should eq 200
resp.body.should eq 'hello, it's me, another test case'

file upload test

conn = Faraday.new('http://localhost') do |http|
  http.request :multipart
  http.request :url_encoded
  http.adapter :test, stubs do |stub|
     stub.post('/upload') { |env| [ 200, {}, {success: true, message: "upload successfully!"} ] }
  end
end

payload = { :file => Faraday::UploadIO.new('~/test.jpg', 'image/jpeg') }
resp = conn.post('/upload', payload)
resp.status.should eq 200
data = JSON.parse(resp.body)
data["success"].should eq true
data["message"].should eq "upload_successfully!"

rest-client

oh, you willl find this gem's test based on webmock.
it looks like this.

stub_request(:get, "www.example.com").to_return(:body => body, :status => 200)
    response = RestClient.get "www.example.com"
    expect(response.code).to eq 200
expect(response.body).to eq body

just do it as webmock.

done!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容