summaryrefslogtreecommitdiff
path: root/doc/development/testing_guide/best_practices.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/testing_guide/best_practices.md')
-rw-r--r--doc/development/testing_guide/best_practices.md62
1 files changed, 50 insertions, 12 deletions
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index a8cbf3aaa5b..32e079f915c 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -51,7 +51,7 @@ bundle exec rspec spec/[path]/[to]/[spec].rb
methods.
- Use `context` to test branching logic.
- Try to match the ordering of tests to the ordering within the class.
-- Try to follow the [Four-Phase Test][four-phase-test] pattern, using newlines
+- Try to follow the [Four-Phase Test](https://thoughtbot.com/blog/four-phase-test) pattern, using newlines
to separate phases.
- Use `Gitlab.config.gitlab.host` rather than hard coding `'localhost'`
- Don't assert against the absolute value of a sequence-generated attribute (see
@@ -62,8 +62,6 @@ bundle exec rspec spec/[path]/[to]/[spec].rb
use a Capyabara matcher beforehand (e.g. `find('.js-foo')`) to ensure the element actually exists.
- Use `focus: true` to isolate parts of the specs you want to run.
-[four-phase-test]: https://robots.thoughtbot.com/four-phase-test
-
### System / Feature tests
NOTE: **Note:** Before writing a new system test, [please consider **not**
@@ -115,7 +113,7 @@ Finished in 34.51 seconds (files took 0.76702 seconds to load)
1 example, 0 failures
```
-Note: `live_debug` only works on javascript enabled specs.
+Note: `live_debug` only works on JavaScript enabled specs.
#### Run `:js` spec in a visible browser
@@ -160,7 +158,7 @@ really fast since:
- Gems loading is skipped
- Rails app boot is skipped
-- gitlab-shell and Gitaly setup are skipped
+- GitLab Shell and Gitaly setup are skipped
- Test repositories setup are skipped
`fast_spec_helper` also support autoloading classes that are located inside the
@@ -185,7 +183,7 @@ instead of 30+ seconds in case of a regular `spec_helper`.
### `let` variables
GitLab's RSpec suite has made extensive use of `let`(along with it strict, non-lazy
-version `let!`) variables to reduce duplication. However, this sometimes [comes at the cost of clarity][lets-not],
+version `let!`) variables to reduce duplication. However, this sometimes [comes at the cost of clarity](https://thoughtbot.com/blog/lets-not),
so we need to set some guidelines for their use going forward:
- `let!` variables are preferable to instance variables. `let` variables
@@ -204,10 +202,51 @@ so we need to set some guidelines for their use going forward:
order is required, otherwise `let` will suffice. Remember that `let` is lazy and won't
be evaluated until it is referenced.
-[lets-not]: https://robots.thoughtbot.com/lets-not
+### Common test setup
+
+In some cases, there is no need to recreate the same object for tests
+again for each example. For example, a project and a guest of that project
+is needed to test issues on the same project, one project and user will do for the entire file.
+This can be achieved by using
+[`let_it_be`](https://test-prof.evilmartians.io/#/let_it_be) variables and the
+[`before_all`](https://test-prof.evilmartians.io/#/before_all) hook
+from the [`test-prof` gem](https://rubygems.org/gems/test-prof).
+
+```
+let_it_be(:project) { create(:project) }
+let_it_be(:user) { create(:user) }
+
+before_all do
+ project.add_guest(user)
+end
+```
+
+This will result in only one `Project`, `User`, and `ProjectMember` created for this context.
+
+`let_it_be` and `before_all` are also available within nested contexts. Cleanup after the context
+is handled automatically using a transaction rollback.
+
+Note that if you modify an object defined inside a `let_it_be` block,
+then you will need to reload the object as needed, or specify the `reload`
+option to reload for every example.
+
+```
+let_it_be(:project, reload: true) { create(:project) }
+```
+
+You can also specify the `refind` option as well to completely load a
+new object.
+
+```
+let_it_be(:project, refind: true) { create(:project) }
+```
### `set` variables
+NOTE: **Note:**
+We are incrementally removing `set` in favour of `let_it_be`. See the
+[removal issue](https://gitlab.com/gitlab-org/gitlab/issues/27922).
+
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
@@ -308,7 +347,7 @@ them unspecified, and look up the value after the row is created.
#### Redis
-GitLab stores two main categories of data in Redis: cached items, and sidekiq
+GitLab stores two main categories of data in Redis: cached items, and Sidekiq
jobs.
In most specs, the Rails cache is actually an in-memory store. This is replaced
@@ -532,7 +571,7 @@ GitLab uses [factory_bot] as a test fixture replacement.
- There should be only one top-level factory definition per file.
- FactoryBot methods are mixed in to all RSpec groups. This means you can (and
should) call `create(...)` instead of `FactoryBot.create(...)`.
-- Make use of [traits] to clean up definitions and usages.
+- Make use of [traits](https://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md#Traits) to clean up definitions and usages.
- When defining a factory, don't define attributes that are not required for the
resulting record to pass validation.
- When instantiating from a factory, don't supply attributes that aren't
@@ -541,7 +580,6 @@ GitLab uses [factory_bot] as a test fixture replacement.
[See example](https://gitlab.com/gitlab-org/gitlab-foss/commit/0b8cefd3b2385a21cfed779bd659978c0402766d).
[factory_bot]: https://github.com/thoughtbot/factory_bot
-[traits]: http://www.rubydoc.info/gems/factory_bot/file/GETTING_STARTED.md#Traits
### Fixtures
@@ -549,9 +587,9 @@ All fixtures should be placed under `spec/fixtures/`.
### Repositories
-Testing some functionality, e.g., merging a merge request, requires a git
+Testing some functionality, e.g., merging a merge request, requires a Git
repository with a certain state to be present in the test environment. GitLab
-maintains the [gitlab-test](https://gitlab.com/gitlab-org/gitlab-test)
+maintains the [`gitlab-test`](https://gitlab.com/gitlab-org/gitlab-test)
repository for certain common cases - you can ensure a copy of the repository is
used with the `:repository` trait for project factories: