File: Transactions.md

package info (click to toggle)
ruby-rspec-rails 7.1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,796 kB
  • sloc: ruby: 11,068; sh: 198; makefile: 6
file content (96 lines) | stat: -rw-r--r-- 2,780 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# 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.

### Disabling transactions

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 transactions:

```ruby
RSpec.configure do |config|
  config.use_transactional_fixtures = false
end
```

### Data created in `before(:example)` are rolled back

Any data you create in a `before(:example)` 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(:example) 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(:example)` hook.

    ```ruby
    before(:context) do
      @widget = Widget.create!
    end

    before(:example) 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.