没有测试的代码就是耍流氓
- rspec(1) - summary
- specs(2) - model
- specs(3) - controller
- specs(4) - request
- specs(5) - mock
- [specs(6) - mailer]
- [specs(7) - view]
- [specs(8) - routing]
- [specs(9) - helper]
- [specs(10) - factory-girl]
- [specs(11) - fake other gems]
- [specs(12) - sidekiq]
- [specs(13) - db migration]
- [specs(14) - timecop]
- [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', '',
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!