在 Gemfile 裡面加入兩個 gem,是寫測試很常用到的工具
factory_bot_rails
以前叫factory_girl_rails
不過後來更名了,是很好用的產生測試資料工具。faker
是很好用的產生假資料工具
group :development, :test do
# ...
gem "factory_bot_rails"
gem "faker"
# ...
end
設定 factory bot
編輯 spec/rails_helper.rb
加入 syntax method
RSpec.configure do |config|
# ...
config.include FactoryBot::Syntax::Methods
# ...
end
建立產生測試資料的檔案
touch spec/factories.rb
FactoryBot.define do
factory :api_access_token do
association :user, factory: [:user]
key { SecureRandom.uuid.delete("-") }
end
factory :user do
email { Faker::Internet.email }
password { "a00000000" }
password_confirmation { "a00000000" }
end
factory :post do
title { Faker::Lorem.question }
context { Faker::Lorem.paragraph_by_chars }
end
end
測試 app/api/api_v0/posts.rb
的 CRUD 行為(這裡先只測成功案例,可以在自行挑戰補上失敗案例)
建立檔案
touch spec/api/api_v0/posts_spec.rb
以下是完整的 CRUD 測試
describe ApiV0::Posts do
before(:all) do
@user = create(:user)
@posts = create_list(:post, 3, user: @user)
@access_token = create(:api_access_token, user: @user)
end
context 'GET /api/v0/posts' do
it 'should return 200 and posts' do
get '/api/v0/posts', params: { access_key: @access_token.key }
result = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(result.size).to eq(@user.posts.size)
end
end
context "Get /api/v0/posts/:id" do
it "return a post by id" do
post = create(:post, user: @user)
get "/api/v0/posts/#{post.id}", params: { access_key: @access_token.key }
result = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(result["title"]).to eq(post.title)
end
end
context "Post /api/v0/posts" do
it "create new post" do
title = "Title"
context = "Context"
post "/api/v0/posts", params: { access_key: @access_token.key, title: title, context: context }
result = JSON.parse(response.body)
expect(response.status).to eq(201)
expect(result["title"]).to eq(title)
expect(result["context"]).to eq(context)
end
end
context "Pacth /api/v0/posts/:id" do
it "update a post by id" do
post = @user.posts.last
title = "Edited title"
context = "Edited context"
patch "/api/v0/posts/#{post.id}", params: { access_key: @access_token.key, title: title, context: context }
result = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(result["title"]).to eq(title)
expect(result["context"]).to eq(context)
end
end
context "Delete /api/v0/posts/:id" do
it "delete a post by id" do
post = @user.posts.last
delete "/api/v0/posts/#{post.id}", params: { access_key: @access_token.key }
result = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(result["title"]).to eq(post.title)
expect(result["context"]).to eq(post.context)
expect{ Post.find(post.id) }.to raise_error ActiveRecord::RecordNotFound
end
end
end
跑跑看結果是不是 all pass?
ApiV0::Ping
GET /api/v0/ping
should return 200 and pong
ApiV0::Posts
GET /api/v0/posts
should return 200 and posts
Get /api/v0/posts/:id
return a post by id
Post /api/v0/posts
create new post
Pacth /api/v0/posts/:id
update a post by id
Delete /api/v0/posts/:id
delete a post by id
Finished in 0.34945 seconds (files took 1.38 seconds to load)
6 examples, 0 failures