diff options
Diffstat (limited to 'doc/development/testing_guide/best_practices.md')
-rw-r--r-- | doc/development/testing_guide/best_practices.md | 62 |
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: |