Use rspec-set to speed up examples

This commit is contained in:
Zeger-Jan van de Weg 2017-04-26 14:46:26 +00:00 committed by Rémy Coutable
parent c7df97710b
commit 6f5b579f94
6 changed files with 58 additions and 34 deletions

View file

@ -293,6 +293,7 @@ group :development, :test do
gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2' gem 'spinach-rerun-reporter', '~> 0.0.2'
gem 'rspec_profiling', '~> 0.0.5' gem 'rspec_profiling', '~> 0.0.5'
gem 'rspec-set', '~> 0.1.3'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0' gem 'minitest', '~> 5.7.0'

View file

@ -659,6 +659,7 @@ GEM
rspec-support (~> 3.5.0) rspec-support (~> 3.5.0)
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-set (0.1.3)
rspec-support (3.5.0) rspec-support (3.5.0)
rspec_profiling (0.0.5) rspec_profiling (0.0.5)
activerecord activerecord
@ -989,6 +990,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0) rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5) rspec_profiling (~> 0.0.5)
rubocop (~> 0.47.1) rubocop (~> 0.47.1)
rubocop-rspec (~> 1.15.0) rubocop-rspec (~> 1.15.0)

View file

@ -202,6 +202,7 @@ Please consult the [dedicated "Frontend testing" guide](./fe_guide/testing.md).
- Try to follow the [Four-Phase Test][four-phase-test] pattern, using newlines - Try to follow the [Four-Phase Test][four-phase-test] pattern, using newlines
to separate phases. to separate phases.
- Try to use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'` - Try to use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'`
- On `before` and `after` hooks, prefer it scoped to `:context` over `:all`
[four-phase-test]: https://robots.thoughtbot.com/four-phase-test [four-phase-test]: https://robots.thoughtbot.com/four-phase-test
@ -225,6 +226,20 @@ so we need to set some guidelines for their use going forward:
[lets-not]: https://robots.thoughtbot.com/lets-not [lets-not]: https://robots.thoughtbot.com/lets-not
#### `set` variables
In some cases there is no need to recreate the same object for tests again for
each example. For example, a project is needed to test issues on the same
project, one project will do for the entire file. This can be achieved by using
`set` in the same way you would use `let`.
`rspec-set` only works on ActiveRecord objects, and before new examples it
reloads or recreates the model, _only_ if needed. That is, when you changed
properties or destroyed the object.
There is one gotcha; you can't reference a model defined in a `let` block in a
`set` block.
### Time-sensitive tests ### Time-sensitive tests
[Timecop](https://github.com/travisjeffery/timecop) is available in our [Timecop](https://github.com/travisjeffery/timecop) is available in our

View file

@ -1,24 +1,24 @@
require 'spec_helper' require 'spec_helper'
describe IssuesFinder do describe IssuesFinder do
let(:user) { create(:user) } set(:user) { create(:user) }
let(:user2) { create(:user) } set(:user2) { create(:user) }
let(:project1) { create(:empty_project) } set(:project1) { create(:empty_project) }
let(:project2) { create(:empty_project) } set(:project2) { create(:empty_project) }
let(:milestone) { create(:milestone, project: project1) } set(:milestone) { create(:milestone, project: project1) }
let(:label) { create(:label, project: project2) } set(:label) { create(:label, project: project2) }
let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone, title: 'gitlab') } set(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone, title: 'gitlab') }
let(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'gitlab') } set(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'gitlab') }
let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2, title: 'tanuki', description: 'tanuki') } set(:issue3) { create(:issue, author: user2, assignee: user2, project: project2, title: 'tanuki', description: 'tanuki') }
describe '#execute' do describe '#execute' do
let(:closed_issue) { create(:issue, author: user2, assignee: user2, project: project2, state: 'closed') } set(:closed_issue) { create(:issue, author: user2, assignee: user2, project: project2, state: 'closed') }
let!(:label_link) { create(:label_link, label: label, target: issue2) } set(:label_link) { create(:label_link, label: label, target: issue2) }
let(:search_user) { user } let(:search_user) { user }
let(:params) { {} } let(:params) { {} }
let(:issues) { IssuesFinder.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute } let(:issues) { IssuesFinder.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute }
before do before(:context) do
project1.team << [user, :master] project1.team << [user, :master]
project2.team << [user, :developer] project2.team << [user, :developer]
project2.team << [user2, :developer] project2.team << [user2, :developer]

View file

@ -3,14 +3,17 @@ require 'spec_helper'
describe API::Issues do describe API::Issues do
include EmailHelpers include EmailHelpers
let(:user) { create(:user) } set(:user) { create(:user) }
set(:project) do
create(:empty_project, :public, creator_id: user.id, namespace: user.namespace)
end
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:non_member) { create(:user) } let(:non_member) { create(:user) }
let(:guest) { create(:user) } set(:guest) { create(:user) }
let(:author) { create(:author) } set(:author) { create(:author) }
let(:assignee) { create(:assignee) } set(:assignee) { create(:assignee) }
let(:admin) { create(:user, :admin) } let(:admin) { create(:user, :admin) }
let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) }
let(:issue_title) { 'foo' } let(:issue_title) { 'foo' }
let(:issue_description) { 'closed' } let(:issue_description) { 'closed' }
let!(:closed_issue) do let!(:closed_issue) do
@ -43,19 +46,19 @@ describe API::Issues do
title: issue_title, title: issue_title,
description: issue_description description: issue_description
end end
let!(:label) do set(:label) do
create(:label, title: 'label', color: '#FFAABB', project: project) create(:label, title: 'label', color: '#FFAABB', project: project)
end end
let!(:label_link) { create(:label_link, label: label, target: issue) } let!(:label_link) { create(:label_link, label: label, target: issue) }
let!(:milestone) { create(:milestone, title: '1.0.0', project: project) } set(:milestone) { create(:milestone, title: '1.0.0', project: project) }
let!(:empty_milestone) do set(:empty_milestone) do
create(:milestone, title: '2.0.0', project: project) create(:milestone, title: '2.0.0', project: project)
end end
let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) } let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) }
let(:no_milestone_title) { URI.escape(Milestone::None.title) } let(:no_milestone_title) { URI.escape(Milestone::None.title) }
before do before(:all) do
project.team << [user, :reporter] project.team << [user, :reporter]
project.team << [guest, :guest] project.team << [guest, :guest]
end end
@ -70,6 +73,8 @@ describe API::Issues do
end end
context "when authenticated" do context "when authenticated" do
let(:first_issue) { json_response.first }
it "returns an array of issues" do it "returns an array of issues" do
get api("/issues", user) get api("/issues", user)
@ -79,46 +84,46 @@ describe API::Issues do
end end
it 'returns an array of closed issues' do it 'returns an array of closed issues' do
get api('/issues?state=closed', user) get api('/issues', user), state: :closed
expect_paginated_array_response(size: 1) expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(closed_issue.id) expect(first_issue['id']).to eq(closed_issue.id)
end end
it 'returns an array of opened issues' do it 'returns an array of opened issues' do
get api('/issues?state=opened', user) get api('/issues', user), state: :opened
expect_paginated_array_response(size: 1) expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(issue.id) expect(first_issue['id']).to eq(issue.id)
end end
it 'returns an array of all issues' do it 'returns an array of all issues' do
get api('/issues?state=all', user) get api('/issues', user), state: :all
expect_paginated_array_response(size: 2) expect_paginated_array_response(size: 2)
expect(json_response.first['id']).to eq(issue.id) expect(first_issue['id']).to eq(issue.id)
expect(json_response.second['id']).to eq(closed_issue.id) expect(json_response.second['id']).to eq(closed_issue.id)
end end
it 'returns issues matching given search string for title' do it 'returns issues matching given search string for title' do
get api("/issues?search=#{issue.title}", user) get api("/issues", user), search: issue.title
expect_paginated_array_response(size: 1) expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(issue.id) expect(json_response.first['id']).to eq(issue.id)
end end
it 'returns issues matching given search string for description' do it 'returns issues matching given search string for description' do
get api("/issues?search=#{issue.description}", user) get api("/issues", user), search: issue.description
expect_paginated_array_response(size: 1) expect_paginated_array_response(size: 1)
expect(json_response.first['id']).to eq(issue.id) expect(first_issue['id']).to eq(issue.id)
end end
it 'returns an array of labeled issues' do it 'returns an array of labeled issues' do
get api("/issues?labels=#{label.title}", user) get api("/issues", user), labels: label.title
expect_paginated_array_response(size: 1) expect_paginated_array_response(size: 1)
expect(json_response.first['labels']).to eq([label.title]) expect(first_issue['labels']).to eq([label.title])
end end
it 'returns an array of labeled issues when all labels matches' do it 'returns an array of labeled issues when all labels matches' do
@ -135,13 +140,13 @@ describe API::Issues do
end end
it 'returns an empty array if no issue matches labels' do it 'returns an empty array if no issue matches labels' do
get api('/issues?labels=foo,bar', user) get api('/issues', user), labels: 'foo,bar'
expect_paginated_array_response(size: 0) expect_paginated_array_response(size: 0)
end end
it 'returns an array of labeled issues matching given state' do it 'returns an array of labeled issues matching given state' do
get api("/issues?labels=#{label.title}&state=opened", user) get api("/issues", user), labels: label.title, state: :opened
expect_paginated_array_response(size: 1) expect_paginated_array_response(size: 1)
expect(json_response.first['labels']).to eq([label.title]) expect(json_response.first['labels']).to eq([label.title])

View file

@ -26,6 +26,7 @@ describe API::MergeRequests do
context "when unauthenticated" do context "when unauthenticated" do
it "returns authentication error" do it "returns authentication error" do
get api("/projects/#{project.id}/merge_requests") get api("/projects/#{project.id}/merge_requests")
expect(response).to have_http_status(401) expect(response).to have_http_status(401)
end end
end end