-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Avoid loading active record fixtures #2869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,21 +1,6 @@ | ||||||||||||||||||||||
| # Pretend that ActiveRecord::Rails is defined and this doesn't blow up | ||||||||||||||||||||||
| # with `config.use_active_record = false`. | ||||||||||||||||||||||
| # Trick the other spec that checks that ActiveRecord is | ||||||||||||||||||||||
| # *not* defined by wrapping it in RSpec::Rails namespace | ||||||||||||||||||||||
| # so that it's reachable from RSpec::Rails::FixtureSupport. | ||||||||||||||||||||||
| # NOTE: this has to be defined before requiring `rails_helper`. | ||||||||||||||||||||||
| module RSpec | ||||||||||||||||||||||
| module Rails | ||||||||||||||||||||||
| module ActiveRecord | ||||||||||||||||||||||
| module TestFixtures | ||||||||||||||||||||||
| end | ||||||||||||||||||||||
| end | ||||||||||||||||||||||
| end | ||||||||||||||||||||||
| end | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| require 'rails_helper' | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| RSpec.describe 'Example App', :use_fixtures, type: :model do | ||||||||||||||||||||||
| RSpec.describe 'Example App', type: :model do | ||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It you revert this spec change, will the old spec still work? If it won’t, why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that using rspec-rails/lib/rspec/rails/configuration.rb Lines 73 to 82 in ef12dbc
It includes Thanks for the suggestion. I'll revert this change. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The global config.include with metadata is a conditional include as far as I recall |
||||||||||||||||||||||
| it "does not set up fixtures" do | ||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This means “we don’t set up fixtures even if AR is loaded and there’s a metadata tag”, right? I hat changed? |
||||||||||||||||||||||
| expect(defined?(fixtures)).not_to be | ||||||||||||||||||||||
| end | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| # Active Record | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer it if you reverted this change, if you want to add to the documentation in another PR or in the original file thats fine, but this is really hard to review what if anything you've changed |
||
|
|
||
| `rspec-rails` by default injects [ActiveSupport::TestCase](https://api.rubyonrails.org/classes/ActiveSupport/TestCase.html) and exposes some of the settings to RSpec configuration. | ||
| Furthermore it adds special hooks into `before` and `after` which are essential for [Active Record Fixtures](https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html) and keeping the database in a clean state. | ||
|
|
||
| It provides the `fixtures` class method in the rspec context to tell Rails which fixtures to prepare before each example. | ||
|
|
||
| In addition to being available in the database, the fixture’s data may also be accessed by using a special dynamic method, which has the same name as the model. | ||
|
|
||
| ```ruby | ||
| RSpec.configure do |config| | ||
| config.fixture_paths = [ | ||
| Rails.root.join('spec/fixtures') | ||
| ] | ||
| end | ||
|
|
||
| RSpec.describe Thing, type: :model do | ||
| fixtures :things | ||
|
|
||
| it "fixture method defined" do | ||
| expect(things(:one)).to eq(Thing.find_by(name: "one")) | ||
| end | ||
| end | ||
| ``` | ||
|
|
||
| More details on how to use fixtures are in the [Rails documentation](https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html#class-ActiveRecord::FixtureSet-label-Using+Fixtures+in+Test+Cases) | ||
|
|
||
| ## Transactions | ||
|
|
||
| When you run `rails generate rspec:install`, the `spec/rails_helper.rb` file | ||
| includes the following configuration: | ||
|
|
||
| ```ruby | ||
| RSpec.configure do |config| | ||
| config.use_transactional_fixtures = true | ||
| end | ||
| ``` | ||
|
|
||
| The name of this setting is a bit misleading. What it really means in Rails | ||
| is "run every test method within a transaction." In the context of rspec-rails, | ||
| it means "run every example within a transaction." | ||
|
|
||
| The idea is to start each example with a clean database, create whatever data | ||
| is necessary for that example, and then remove that data by simply rolling back | ||
| the transaction at the end of the example. | ||
|
|
||
| For how this affects methods exposing transaction visibility see: | ||
| https://guides.rubyonrails.org/testing.html#transactions | ||
|
|
||
| ### Data created in `before` are rolled back | ||
|
|
||
| Any data you create in a `before` hook will be rolled back at the end of | ||
| the example. This is a good thing because it means that each example is | ||
| isolated from state that would otherwise be left around by the examples that | ||
| already ran. For example: | ||
|
|
||
| ```ruby | ||
| describe Widget do | ||
| before do | ||
| @widget = Widget.create | ||
| end | ||
|
|
||
| it "does something" do | ||
| expect(@widget).to do_something | ||
| end | ||
|
|
||
| it "does something else" do | ||
| expect(@widget).to do_something_else | ||
| end | ||
| end | ||
| ``` | ||
|
|
||
| The `@widget` is recreated in each of the two examples above, so each example | ||
| has a different object, _and_ the underlying data is rolled back so the data | ||
| backing the `@widget` in each example is new. | ||
|
|
||
| ### Data created in `before(:context)` are _not_ rolled back | ||
|
|
||
| `before(:context)` hooks are invoked before the transaction is opened. You can use | ||
| this to speed things up by creating data once before any example in a group is | ||
| run, however, this introduces a number of complications and you should only do | ||
| this if you have a firm grasp of the implications. Here are a couple of | ||
| guidelines: | ||
|
|
||
| 1. Be sure to clean up any data in an `after(:context)` hook: | ||
|
|
||
| ```ruby | ||
| before(:context) do | ||
| @widget = Widget.create! | ||
| end | ||
|
|
||
| after(:context) do | ||
| @widget.destroy | ||
| end | ||
| ``` | ||
|
|
||
| If you don't do that, you'll leave data lying around that will eventually | ||
| interfere with other examples. | ||
|
|
||
| 2. Reload the object in a `before` hook. | ||
|
|
||
| ```ruby | ||
| before(:context) do | ||
| @widget = Widget.create! | ||
| end | ||
| before do | ||
| @widget.reload | ||
| end | ||
| ``` | ||
|
|
||
| Even though database updates in each example will be rolled back, the | ||
| object won't _know_ about those rollbacks so the object and its backing | ||
| data can easily get out of sync. | ||
| ## Configuration | ||
| ### Disabling Active Record support | ||
| If you prefer to manage the data yourself, or using another tool like | ||
| [database_cleaner](https://github.com/bmabey/database_cleaner) to do it for you, | ||
| simply tell RSpec to tell Rails not to manage fixtures and cleaning database. | ||
| ```ruby | ||
| RSpec.configure do |config| | ||
| config.use_active_record = false # is true by default | ||
| end | ||
| ``` | ||
| ### Fixtures path | ||
| The generator will provide the default path to the fixture, but it is possible to change it: | ||
| ```ruby | ||
| RSpec.configure do |config| | ||
| config.fixture_paths = Rails.root.join('some/dir') # Rails.root.join('spec/fixtures') by default | ||
| end | ||
| ``` | ||
| ### Instantiated fixtures | ||
| If you want to have your fixtures available as an instance variable in the example, you could use `use_instantiated_fixtures` option: | ||
| ```ruby | ||
| RSpec.configure do |config| | ||
| config.use_instantiated_fixtures = true # false, by default | ||
| end | ||
| RSpec.describe Thing, type: :model do | ||
| fixtures :things | ||
| it "instantiates fixtures" do | ||
| expect(@things["one"]).to eq(@one) | ||
| end | ||
| end | ||
| ``` | ||
| ### Global fixtures | ||
| Sometimes it is required to have some fixture in each example, and it's possible to do this via `global_fixtures` setting: | ||
|
|
||
| ```ruby | ||
| RSpec.configure do |config| | ||
| config.global_fixtures = [:things] | ||
| end | ||
| RSpec.describe Thing, type: :model do | ||
| it "inserts fixture" do | ||
| expect(things(:one)).to be_a(Thing) | ||
| end | ||
| end | ||
| ``` | ||
|
|
||
| ### Disabling transactions | ||
|
|
||
| If your database does not support transactions, but you still want to use Rails fixtures, it is possible to disable transactions explicitly: | ||
|
|
||
| ```ruby | ||
| RSpec.configure do |config| | ||
| config.use_transactional_fixtures = false | ||
| end | ||
| ``` | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,12 +45,11 @@ | |
| Rails.root.join('spec/fixtures') | ||
| ] | ||
| # If you're not using ActiveRecord, or you'd prefer not to run each of your | ||
| # examples within a transaction, remove the following line or assign false | ||
| # instead of true. | ||
| # If you'd prefer not to run each of your examples within a transaction, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why remove the mention of AR here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, originally this statement is not quite correct, specifically the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer it if this was reverted, you should delete this setting if you're not using ActiveRecord, thats why it's written that way. |
||
| # remove the following line or assign false instead of true. | ||
| config.use_transactional_fixtures = true | ||
| # You can uncomment this line to turn off ActiveRecord support entirely. | ||
| # You can uncomment this line to turn off ActiveRecord support entirely | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Revert this change please. |
||
| # config.use_active_record = false | ||
| <% else -%> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to remain, see the documentation comment, it exists to test that stuff doesn't happen when the flag is set to false and the module is defined, this is because even though we can exclude active record, it often still exists due to dependencies, but hasn't been configured...