test_data 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +15 -15
- data/LICENSE.txt +1 -6
- data/README.md +652 -276
- data/example/Gemfile.lock +73 -73
- data/example/test/integration/better_mode_switching_demo_test.rb +4 -0
- data/example/test/integration/parallel_boops_with_fixtures_test.rb +2 -2
- data/example/test/integration/parallel_boops_without_fixtures_test.rb +2 -2
- data/example/test/integration/rails_fixtures_double_load_test.rb +10 -0
- data/example/test/integration/rails_fixtures_override_test.rb +127 -0
- data/example/test/integration/transaction_committing_boops_test.rb +14 -3
- data/example/test/test_helper.rb +2 -2
- data/lib/generators/test_data/cable_yaml_generator.rb +18 -0
- data/lib/generators/test_data/database_yaml_generator.rb +2 -3
- data/lib/generators/test_data/environment_file_generator.rb +3 -0
- data/lib/generators/test_data/initializer_generator.rb +7 -0
- data/lib/generators/test_data/secrets_yaml_generator.rb +19 -0
- data/lib/generators/test_data/webpacker_yaml_generator.rb +3 -2
- data/lib/test_data.rb +5 -0
- data/lib/test_data/active_record_ext.rb +11 -0
- data/lib/test_data/config.rb +14 -2
- data/lib/test_data/configurators.rb +2 -0
- data/lib/test_data/configurators/cable_yaml.rb +25 -0
- data/lib/test_data/configurators/environment_file.rb +3 -2
- data/lib/test_data/configurators/initializer.rb +3 -2
- data/lib/test_data/configurators/secrets_yaml.rb +25 -0
- data/lib/test_data/configurators/webpacker_yaml.rb +4 -3
- data/lib/test_data/dumps_database.rb +24 -1
- data/lib/test_data/generator_support.rb +3 -0
- data/lib/test_data/loads_database_dumps.rb +1 -1
- data/lib/test_data/log.rb +19 -1
- data/lib/test_data/rake.rb +16 -6
- data/lib/test_data/statistics.rb +6 -1
- data/lib/test_data/transactional_data_loader.rb +156 -46
- data/lib/test_data/version.rb +1 -1
- data/script/test +11 -0
- data/test_data.gemspec +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 492abd0bddc1329c073d45cb984dd60aa374f3520c6d3362bec34ece165f0407
|
4
|
+
data.tar.gz: efee863beeba57aa27e98d8b833ca0398d022baaa710b8a741d8da3995a71dce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1796bcb024853380c7a387f5f69d8b564ca78c4318fbf0a3c526546c5000fb5f676cc846a0541443c5d53e664f3b74d1970df4526d12b7f931209e9d78cdb684
|
7
|
+
data.tar.gz: b77b0c1a24a806ac817d516173a6f68b9e7d63ca088bae6cc32de41c688df0c296a1eedf7e7bde81ce46faba76301b98fde0f1fd1a2ccc1842f9095fdbafc132
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# unreleased
|
2
|
+
|
3
|
+
- New feature: `TestData.load_rails_fixtures` to override default fixtures
|
4
|
+
behavior by loading it in a nested transaction after `TestData.truncate`
|
5
|
+
- Breaking change: move transactions configuration out of `TestData.load` and
|
6
|
+
instead a global setting for `TestData.config` named
|
7
|
+
`use_transactional_data_loader`
|
8
|
+
- Cascades truncation of test_data tables unless they're explicitly specified by
|
9
|
+
the truncate_these_test_data_tables` option
|
10
|
+
- Add secrets.yml and cable.yml generators to `test_data:configure` task
|
11
|
+
- Print the size of each dump and warn when dump size reaches certain thresholds
|
12
|
+
or increases significantly in the `test_data:dump` task
|
13
|
+
|
1
14
|
# 0.0.2
|
2
15
|
|
3
16
|
- Make the rest of the gem better
|
data/Gemfile.lock
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
test_data (0.0
|
4
|
+
test_data (0.1.0)
|
5
5
|
railties (~> 6.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
actionpack (6.1.
|
11
|
-
actionview (= 6.1.
|
12
|
-
activesupport (= 6.1.
|
10
|
+
actionpack (6.1.4)
|
11
|
+
actionview (= 6.1.4)
|
12
|
+
activesupport (= 6.1.4)
|
13
13
|
rack (~> 2.0, >= 2.0.9)
|
14
14
|
rack-test (>= 0.6.3)
|
15
15
|
rails-dom-testing (~> 2.0)
|
16
16
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
17
|
-
actionview (6.1.
|
18
|
-
activesupport (= 6.1.
|
17
|
+
actionview (6.1.4)
|
18
|
+
activesupport (= 6.1.4)
|
19
19
|
builder (~> 3.1)
|
20
20
|
erubi (~> 1.4)
|
21
21
|
rails-dom-testing (~> 2.0)
|
22
22
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
23
|
-
activesupport (6.1.
|
23
|
+
activesupport (6.1.4)
|
24
24
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
25
25
|
i18n (>= 1.6, < 2)
|
26
26
|
minitest (>= 5.1)
|
@@ -29,18 +29,18 @@ GEM
|
|
29
29
|
ast (2.4.2)
|
30
30
|
builder (3.2.4)
|
31
31
|
coderay (1.1.3)
|
32
|
-
concurrent-ruby (1.1.
|
32
|
+
concurrent-ruby (1.1.9)
|
33
33
|
crass (1.0.6)
|
34
34
|
erubi (1.10.0)
|
35
35
|
i18n (1.8.10)
|
36
36
|
concurrent-ruby (~> 1.0)
|
37
|
-
loofah (2.
|
37
|
+
loofah (2.10.0)
|
38
38
|
crass (~> 1.0.2)
|
39
39
|
nokogiri (>= 1.5.9)
|
40
40
|
method_source (1.0.0)
|
41
|
-
mini_portile2 (2.5.
|
41
|
+
mini_portile2 (2.5.3)
|
42
42
|
minitest (5.14.4)
|
43
|
-
nokogiri (1.11.
|
43
|
+
nokogiri (1.11.7)
|
44
44
|
mini_portile2 (~> 2.5.0)
|
45
45
|
racc (~> 1.4)
|
46
46
|
parallel (1.20.1)
|
@@ -58,11 +58,11 @@ GEM
|
|
58
58
|
nokogiri (>= 1.6)
|
59
59
|
rails-html-sanitizer (1.3.0)
|
60
60
|
loofah (~> 2.3)
|
61
|
-
railties (6.1.
|
62
|
-
actionpack (= 6.1.
|
63
|
-
activesupport (= 6.1.
|
61
|
+
railties (6.1.4)
|
62
|
+
actionpack (= 6.1.4)
|
63
|
+
activesupport (= 6.1.4)
|
64
64
|
method_source
|
65
|
-
rake (>= 0.
|
65
|
+
rake (>= 0.13)
|
66
66
|
thor (~> 1.0)
|
67
67
|
rainbow (3.0.0)
|
68
68
|
rake (13.0.3)
|
data/LICENSE.txt
CHANGED
@@ -1,9 +1,4 @@
|
|
1
|
-
Copyright (c)
|
2
|
-
|
3
|
-
Portions of these files Copyright (c) 2012-18 Bozhidar Batsov:
|
4
|
-
- config/base.yml
|
5
|
-
- lib/standard/cop/block_single_line_braces.rb
|
6
|
-
- test/cop_invoker.rb
|
1
|
+
Copyright (c) 2022 Test Double, LLC
|
7
2
|
|
8
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
9
4
|
a copy of this software and associated documentation files (the
|
data/README.md
CHANGED
@@ -1,48 +1,99 @@
|
|
1
1
|
# The `test_data` gem
|
2
2
|
|
3
|
-
`test_data`
|
4
|
-
your Rails application's test data.
|
3
|
+
`test_data` does what it says on the tin: it provides a fast & reliable system
|
4
|
+
for managing your Rails application's test data.
|
5
5
|
|
6
6
|
The gem serves as both an alternative to
|
7
7
|
[fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
|
8
8
|
& [factory_bot](https://github.com/thoughtbot/factory_bot), as well a broader
|
9
|
-
workflow for building
|
10
|
-
|
9
|
+
workflow for building test suites that will scale gracefully as your application
|
10
|
+
grows in size and complexity.
|
11
11
|
|
12
12
|
What it does:
|
13
13
|
|
14
|
-
* Establishes a fourth Rails environment
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
* Establishes a fourth Rails environment (you can [define custom Rails
|
15
|
+
environments](https://guides.rubyonrails.org/configuring.html#creating-rails-environments)!)
|
16
|
+
named `test_data`, which you'll use to create a universe of data for your
|
17
|
+
tests by simply running and using your application. No Ruby DSL, no YAML
|
18
|
+
files, no precarious approximations of realism: **real data created by your
|
19
|
+
app**
|
18
20
|
|
19
21
|
* Exposes a simple API for loading your test data and cleaning up between
|
20
|
-
tests. Common edge cases are handled
|
22
|
+
tests. Common edge cases are handled seamlessly. Tests that need access to
|
21
23
|
your data will see it and tests that don't, won't
|
22
24
|
|
23
|
-
* Safeguards your tests from flaky failures and supercharges
|
24
|
-
providing a sophisticated transaction manager that isolates each test
|
25
|
-
|
25
|
+
* Safeguards your tests from flaky failures and supercharges your build by
|
26
|
+
providing a sophisticated transaction manager that isolates each test while
|
27
|
+
ensuring your data is only loaded once
|
26
28
|
|
27
29
|
If you've despaired over the seeming inevitability that all Rails test suites
|
28
|
-
will eventually grow to become slow,
|
29
|
-
for you! And even if you're [a factory_bot
|
30
|
+
will eventually grow to become slow, incomprehensible, and brittle, then this
|
31
|
+
gem is for you! And even if you're [a factory_bot
|
30
32
|
fan](https://twitter.com/searls/status/1379491813099253762?s=20), we hope you'll
|
31
33
|
be open to the idea that [there might be a better way](
|
32
34
|
#but-we-use-and-like-factory_bot-and-so-i-am-inclined-to-dislike-everything-about-this-gem).
|
33
35
|
|
34
|
-
_[
|
36
|
+
_[Full disclosure: because the gem is still brand new, it makes a number of
|
35
37
|
[assumptions](#assumptions) and may not work for every project just yet.]_
|
36
38
|
|
39
|
+
## Documentation
|
40
|
+
|
41
|
+
This gem requires a lot of documentation—not because `test_data` does a lot of
|
42
|
+
things, but because managing one's test data is an inherently complex task. If
|
43
|
+
one reason Rails apps chronically suffer from slow tests is that other
|
44
|
+
approaches oversimplify test data management, it stands to reason that any
|
45
|
+
discomfort caused by `test_data`'s scope may not indicate _unnecessary
|
46
|
+
complexity_ so much as highlight how much acclimatization is needed to adopt the
|
47
|
+
necessary diligence to achieve fast, isolated tests that scale with your
|
48
|
+
application.
|
49
|
+
|
50
|
+
1. [Getting Started Guide](#getting-started-guide)
|
51
|
+
1. [Install and initialize
|
52
|
+
`test_data`](#step-1-install-and-initialize-test_data)
|
53
|
+
2. [Create some test data](#step-2-create-some-test-data)
|
54
|
+
3. [Dump your `test_data` database](#step-3-dump-your-test_data-database)
|
55
|
+
4. [Load your data in your tests](#step-4-load-your-data-in-your-tests)
|
56
|
+
5. [Keeping your test data
|
57
|
+
up-to-date](#step-5-keeping-your-test-data-up-to-date)
|
58
|
+
2. [Factory & Fixture Interoperability
|
59
|
+
Guide](#factory--fixture-interoperability-guide)
|
60
|
+
* [Using `test_data` with `factory_bot`](#using-test_data-with-factory_bot)
|
61
|
+
* [Using `test_data` with Rails fixtures](#using-test_data-with-rails-fixtures)
|
62
|
+
3. [Rake Task Reference](#rake-task-reference)
|
63
|
+
* [test_data:install](#test_datainstall)
|
64
|
+
* [test_data:configure](#test_dataconfigure)
|
65
|
+
* [test_data:verify_config](#test_dataverify_config)
|
66
|
+
* [test_data:initialize](#test_datainitialize)
|
67
|
+
* [test_data:dump](#test_datadump)
|
68
|
+
* [test_data:load](#test_dataload)
|
69
|
+
* [test_data:create_database](#test_datacreate_database)
|
70
|
+
* [test_data:drop_database](#test_datadrop_database)
|
71
|
+
4. [API Reference](#api-reference)
|
72
|
+
* [TestData.config](#testdataconfig)
|
73
|
+
* [TestData.load](#testdataload)
|
74
|
+
* [TestData.rollback](#testdatarollback)
|
75
|
+
* [TestData.rollback(:before_data_load)](#rolling-back-to-before-test-data-was-loaded)
|
76
|
+
* [TestData.rollback(:after_data_load)](#rolling-back-to-after-the-data-was-loaded)
|
77
|
+
* [TestData.rollback(:after_data_truncate)](#rolling-back-to-after-test-data-was-truncated)
|
78
|
+
* [TestData.rollback(:after_load_rails_fixtures)](#rolling-back-to-after-rails-fixtures-were-loaded)
|
79
|
+
* [TestData.truncate](#testdatatruncate)
|
80
|
+
* [TestData.prevent_rails_fixtures_from_loading_automatically!](#testdataprevent_rails_fixtures_from_loading_automatically)
|
81
|
+
* [TestData.load_rails_fixtures](#testdataload_rails_fixtures)
|
82
|
+
5. [Assumptions](#assumptions)
|
83
|
+
6. [Fears, Uncertainties, and Doubts](#fears-uncertainties-and-doubts) (Q & A)
|
84
|
+
7. [Code of Conduct](#code-of-conduct)
|
85
|
+
8. [Changelog](/CHANGELOG.md)
|
86
|
+
9. [MIT License](/LICENSE.txt)
|
87
|
+
|
37
88
|
## Getting started guide
|
38
89
|
|
39
90
|
This guide will walk you through setting up `test_data` in your application. You
|
40
91
|
might notice that it's more complicated than installing a gem and declaring some
|
41
|
-
default `Widget` attributes! The truth is that designing robust and
|
42
|
-
test data
|
43
|
-
are plenty of shortcuts available, but experience has shown they
|
44
|
-
collapse under their own weight as your app scales and your team
|
45
|
-
when fast & reliable tests
|
92
|
+
default `Widget` attributes! The hard truth is that designing robust and
|
93
|
+
reliable test data is an inherently complex problem and takes some thoughtful
|
94
|
+
planning. There are plenty of shortcuts available, but experience has shown they
|
95
|
+
tend to collapse under their own weight as your app scales and your team
|
96
|
+
grows—exactly when having a suite of fast & reliable tests is most valuable.
|
46
97
|
|
47
98
|
And if you get stuck or need help as you're getting started, please feel free to
|
48
99
|
[ask us for help](https://github.com/testdouble/test_data/discussions/new)!
|
@@ -62,14 +113,15 @@ end
|
|
62
113
|
```
|
63
114
|
|
64
115
|
Since the `test_data` environment is designed to be used similarly to
|
65
|
-
`development` (i.e. with a running server and interacting via a browser)
|
66
|
-
`:
|
67
|
-
|
116
|
+
`development` (i.e. with a running server and interacting via a browser), any
|
117
|
+
gems in your `:development` gem group should likely be included in a
|
118
|
+
`:test_data` gem group as well.
|
68
119
|
|
69
120
|
#### Configuring the gem and initializing the database
|
70
121
|
|
71
|
-
The gem ships with a number of Rake tasks, including
|
72
|
-
will generate the necessary
|
122
|
+
The gem ships with a number of Rake tasks, including
|
123
|
+
[test_data:install](#test_datainstall), which will generate the necessary
|
124
|
+
configuration and initialize a `test_data` database:
|
73
125
|
|
74
126
|
```
|
75
127
|
$ bin/rake test_data:install
|
@@ -118,6 +170,10 @@ environment variable:
|
|
118
170
|
$ RAILS_ENV=test_data bin/rails server
|
119
171
|
```
|
120
172
|
|
173
|
+
_[If you're using [webpacker](https://github.com/rails/webpacker), you may also
|
174
|
+
need to start its development server as well with `RAILS_ENV=test_data
|
175
|
+
bin/webpack-dev-server`]_
|
176
|
+
|
121
177
|
Because `test_data` creates a full-fledged Rails environment, you can run any
|
122
178
|
number of Rails commands or Rake tasks against its database by setting
|
123
179
|
`RAILS_ENV=test_data`, either in your shell environment or with each command
|
@@ -173,14 +229,16 @@ everything looks good—commit them. (And if the files are gigantic or full of
|
|
173
229
|
noise, you might find [these ideas
|
174
230
|
helpful](#are-you-sure-i-should-commit-these-sql-dumps-theyre-way-too-big)).
|
175
231
|
|
176
|
-
|
177
|
-
skeptical](https://twitter.com/searls/status/860553435116187649?s=20)
|
178
|
-
you're asked to commit a generated file! Remember that the `test_data`
|
232
|
+
Does it feel weird to dump and commit SQL files? That's okay! It's [healthy to
|
233
|
+
be skeptical](https://twitter.com/searls/status/860553435116187649?s=20)
|
234
|
+
whenever you're asked to commit a generated file! Remember that the `test_data`
|
179
235
|
environment exists only for creating your test data. Your tests will, in turn,
|
180
236
|
load the SQL dump of your data into the familiar `test` database, and things
|
181
237
|
will proceed just as if you'd been loading [Rails' built-in
|
182
238
|
fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
|
183
|
-
from a set of YAML files—the major difference being
|
239
|
+
from a set of YAML files—the major difference being that `test_data` databases
|
240
|
+
are generated through realistic use, whereas fixtures are defined manually in
|
241
|
+
(sometimes painstaking) YAML.
|
184
242
|
|
185
243
|
### Step 4: Load your data in your tests
|
186
244
|
|
@@ -189,9 +247,9 @@ writing tests that rely on this test data.
|
|
189
247
|
|
190
248
|
To accomplish this, you'll likely want to add hooks to run before & after each
|
191
249
|
test—first to load your test data and then to rollback any changes made by the
|
192
|
-
test. The `test_data` gem
|
193
|
-
[TestData.load](#testdataload) and
|
194
|
-
methods.
|
250
|
+
test in order to clear the air for the next test. The `test_data` gem
|
251
|
+
accomplishes this with its [TestData.load](#testdataload) and
|
252
|
+
[TestData.rollback](#testdatarollback) methods.
|
195
253
|
|
196
254
|
If you're using (Rails' default)
|
197
255
|
[Minitest](https://github.com/seattlerb/minitest) and want to include your test
|
@@ -199,11 +257,11 @@ data with every test, you can add these hooks to `ActiveSupport::TestCase`:
|
|
199
257
|
|
200
258
|
```ruby
|
201
259
|
class ActiveSupport::TestCase
|
202
|
-
|
260
|
+
setup do
|
203
261
|
TestData.load
|
204
262
|
end
|
205
263
|
|
206
|
-
|
264
|
+
teardown do
|
207
265
|
TestData.rollback
|
208
266
|
end
|
209
267
|
end
|
@@ -224,47 +282,52 @@ RSpec.configure do |config|
|
|
224
282
|
end
|
225
283
|
```
|
226
284
|
|
227
|
-
That should be all you need to have access to your test data in
|
228
|
-
tests
|
229
|
-
always-rolled-back transaction. For more
|
230
|
-
the [API reference](#api-reference).
|
285
|
+
That should be all you need to have access to your test data in each of your
|
286
|
+
tests! Your tests will also benefit from the speed and data integrity that comes
|
287
|
+
with wrapping each test in an always-rolled-back transaction. For more
|
288
|
+
information on how all this works, see the [API reference](#api-reference). If
|
289
|
+
your test suite is already using fixtures or factories and the above hooks just
|
290
|
+
broke everything, check out our [interoperability
|
291
|
+
guide](#factory--fixture-interoperability-guide) for help.
|
231
292
|
|
232
293
|
If you _don't_ want all of your Rails-aware tests to see this test data (suppose
|
233
|
-
you have existing tests that use factories
|
294
|
+
you have existing tests that use factories instead), you probably
|
234
295
|
want to use [TestData.truncate](#testdatatruncate) to clear data generated by
|
235
296
|
this gem out before they run. You might do that by defining two test types:
|
236
297
|
|
237
298
|
```ruby
|
238
299
|
# Tests using data created by `test_data`
|
239
300
|
class TestDataTestCase < ActiveSupport::TestCase
|
240
|
-
|
301
|
+
setup do
|
241
302
|
TestData.load
|
242
303
|
end
|
243
304
|
|
244
|
-
|
305
|
+
teardown do
|
245
306
|
TestData.rollback
|
246
307
|
end
|
247
308
|
end
|
248
309
|
|
249
|
-
# Tests
|
250
|
-
class
|
251
|
-
|
252
|
-
|
253
|
-
def setup
|
310
|
+
# Tests that don't need a shared data source
|
311
|
+
class SomeModelTestCase < ActiveSupport::TestCase
|
312
|
+
setup do
|
254
313
|
TestData.truncate
|
255
314
|
end
|
256
315
|
|
257
|
-
def
|
316
|
+
def test_some_model_does_stuff
|
317
|
+
some_model = SomeModel.create!
|
318
|
+
|
319
|
+
result = some_model.does_stuff
|
320
|
+
|
321
|
+
assert_equal :cool_stuff, result
|
322
|
+
end
|
323
|
+
|
324
|
+
teardown do
|
258
325
|
TestData.rollback(:after_data_truncate)
|
259
326
|
end
|
260
327
|
end
|
261
328
|
|
262
329
|
```
|
263
330
|
|
264
|
-
For more thoughts on migrating to `test_data` when you have existing tests,
|
265
|
-
[some ideas are discussed
|
266
|
-
here](#we-already-have-thousands-of-tests-that-depend-on-rails-fixtures-or-factory_bot-can-we-start-using-test_data-without-throwing-them-away-and-starting-over).
|
267
|
-
|
268
331
|
### Step 5: Keeping your test data up-to-date
|
269
332
|
|
270
333
|
Because your app relies on its tests and your tests rely on their test data,
|
@@ -282,17 +345,18 @@ data. Here's a rough outline to updating your `test_data` database:
|
|
282
345
|
1. If your local `test_data` database is out-of-date with your latest SQL dump
|
283
346
|
files, drop it with `rake test_data:drop_database`
|
284
347
|
|
285
|
-
2. Load your schema & data into the database with `rake
|
348
|
+
2. Load your schema & data into the `test_data` database with `rake
|
349
|
+
test_data:load`
|
286
350
|
|
287
351
|
3. Run any pending migrations with `RAILS_ENV=test_data bin/rake db:migrate`
|
288
352
|
|
289
353
|
4. If you need to create any additional data, start up the server
|
290
|
-
(`RAILS_ENV=test_data bin/rails s`), just like [Step
|
354
|
+
(`RAILS_ENV=test_data bin/rails s`), just like in [Step
|
291
355
|
2](#step-2-create-some-test-data)
|
292
356
|
|
293
357
|
5. Export your newly-updated `test_data` database with `rake test_data:dump`
|
294
358
|
|
295
|
-
6. Ensure your tests are passing and commit the resulting SQL files
|
359
|
+
6. Ensure your tests are passing and then commit the resulting SQL files
|
296
360
|
|
297
361
|
It's important to keep in mind that your test data SQL dumps are a shared,
|
298
362
|
generated resource among your team (just like a `structure.sql` or `schema.rb`
|
@@ -309,6 +373,361 @@ time of things if you use migrations for both schema and data changes. Here are
|
|
309
373
|
some notes on [how to write data migrations
|
310
374
|
safely](https://blog.testdouble.com/posts/2014-11-04-healthy-migration-habits/#habit-4-dont-reference-models).]_
|
311
375
|
|
376
|
+
## Factory & Fixture Interoperability Guide
|
377
|
+
|
378
|
+
Let's be real, most Rails apps already have some tests, and most of those test
|
379
|
+
suites will already be relying on
|
380
|
+
[factory_bot](https://github.com/thoughtbot/factory_bot) or Rails' built-in
|
381
|
+
[test
|
382
|
+
fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures).
|
383
|
+
While `test_data` is designed to be an alternative to both of these approaches
|
384
|
+
to managing your test data, it wouldn't be practical to ask a team to rewrite
|
385
|
+
all their existing tests in order to migrate to a different tool. That's why the
|
386
|
+
`test_data` gem goes to great lengths to play nicely with your existing tests,
|
387
|
+
while ensuring each test is wrapped in an isolated and fast always-rolled-back
|
388
|
+
transaction—regardless if the test depends on `test_data`, factories, fixtures,
|
389
|
+
all three, or none-of-the-above.
|
390
|
+
|
391
|
+
This section will hopefully make it a little easier to incorporate new
|
392
|
+
`test_data` tests into a codebase that's already using `factory_bot` and/or
|
393
|
+
Rails fixtures, whether you choose to incrementally rewrite the older tests to
|
394
|
+
conform to your `test_data` or not.
|
395
|
+
|
396
|
+
### Using `test_data` with `factory_bot`
|
397
|
+
|
398
|
+
This section will document some thoughts and strategies for introducing
|
399
|
+
`test_data` to a test suite that's already using `factory_bot`.
|
400
|
+
|
401
|
+
#### Getting your factory tests passing after adding `test_data`
|
402
|
+
|
403
|
+
Depending on the assumptions your tests make about the state of the database
|
404
|
+
before you've loaded any factories, it's possible that everything will "just
|
405
|
+
work" after adding `TestData.load` in a before-each hook and `TestData.rollback`
|
406
|
+
in an after-each hook (as shown in the [setup
|
407
|
+
guide](#step-4-load-your-data-in-your-tests)). So by all means, try running your
|
408
|
+
suite after following the initial setup guide and see if the suite just passes.
|
409
|
+
|
410
|
+
If you find that your test suite is failing after adding `TestData.load` to your
|
411
|
+
setup, don't panic! It probably means that you have test data and factory
|
412
|
+
invocations that are, when combined, violating unique validations or database
|
413
|
+
constraints. Depending on your situation (e.g. the size of your test suite, how
|
414
|
+
well you understand the intentions of older tests) you might try to resolve
|
415
|
+
these errors one-by-one, usually by updating the offending factories or
|
416
|
+
editing your `test_data` database to ensure they steer clear of one another.
|
417
|
+
This can be tedious, however, and can undermine the completeness of either data
|
418
|
+
source in the absence of the other.
|
419
|
+
|
420
|
+
If your tests are failing after introducing `test_data` and it's not desirable
|
421
|
+
or feasible to work through the individual failures, you can accomplish a clean
|
422
|
+
segregation between your factory-dependent tests and your tests that rely on
|
423
|
+
`test_data` by wrapping each test that depends on `factory_bot` with
|
424
|
+
[TestData.truncate](#testdatatruncate) in a before-each hook and
|
425
|
+
[TestData.rollback(:after_data_truncate)](#rolling-back-to-after-test-data-was-truncated)
|
426
|
+
in an after-each hook, like this:
|
427
|
+
|
428
|
+
```ruby
|
429
|
+
class AnExistingFactoryUsingTest < ActiveSupport::Testcase
|
430
|
+
def setup
|
431
|
+
TestData.truncate
|
432
|
+
# pre-existing setup
|
433
|
+
end
|
434
|
+
|
435
|
+
def test_stuff
|
436
|
+
#… etc
|
437
|
+
end
|
438
|
+
|
439
|
+
def teardown
|
440
|
+
TestData.rollback(:after_truncate)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
```
|
444
|
+
|
445
|
+
What this will do is complicated and counter-intuitive, but also fast and
|
446
|
+
reliable: [TestData.truncate](#testdatatruncate) will first ensure that your
|
447
|
+
`test_data` database is loaded inside a transaction, then will truncate that
|
448
|
+
data (set the `truncate_these_test_data_tables` [config option](#testdataconfig)
|
449
|
+
if necessary), and will finally create _yet another_ transaction save point
|
450
|
+
named `:after_data_truncate`. From that point onward, your test is free to
|
451
|
+
create all the factories it needs without fear of colliding with whatever you've
|
452
|
+
got stored in your `test_data` tables.
|
453
|
+
|
454
|
+
_[Why does this approach potentially load all the `test_data` data only to
|
455
|
+
immediately truncate it? Because it's actually much faster to truncate a large
|
456
|
+
data load in a live transaction, rollback the truncation, and then re-truncate
|
457
|
+
the data for a subsequent test than it would be to rollback the large data load
|
458
|
+
itself and re-load it for a subsequent test. It's silly but it works.]_
|
459
|
+
|
460
|
+
Hopefully one of these approaches, or some combination of them will get your
|
461
|
+
test suite passing after you've introduced `test_data`.
|
462
|
+
|
463
|
+
#### Separating your `test_data` and factory tests
|
464
|
+
|
465
|
+
Just because your tests _can_ access both your `factory_bot` factories and
|
466
|
+
`test_data` database doesn't mean they _should_.
|
467
|
+
|
468
|
+
Integration tests inevitably become coupled to the data that's available to
|
469
|
+
them, and if a test has access to both records created by a factory and a
|
470
|
+
`test_data` SQL dump, it is likely to unintentionally become inextricable from
|
471
|
+
both. This could result in the test having more ways to fail than necessary and
|
472
|
+
make it harder to simplify your test data strategy later. Instead, consider
|
473
|
+
explicitly opting into a single type of test data by separating your tests based
|
474
|
+
on which source of test data they use.
|
475
|
+
|
476
|
+
Every situation will be different, but one strategy that suits a lot of
|
477
|
+
circumstances would be to write a class method that runs at test-load time to
|
478
|
+
declare and configure the test data strategy for the current test.
|
479
|
+
|
480
|
+
Taking from [this
|
481
|
+
example](/example/test/integration/better_mode_switching_demo_test.rb) test, you
|
482
|
+
could implement a class method like this:
|
483
|
+
|
484
|
+
```ruby
|
485
|
+
class ActiveSupport::TestCase
|
486
|
+
def self.test_data_mode(mode)
|
487
|
+
case mode
|
488
|
+
when :factory_bot
|
489
|
+
require "factory_bot_rails"
|
490
|
+
include FactoryBot::Syntax::Methods
|
491
|
+
|
492
|
+
setup do
|
493
|
+
TestData.truncate
|
494
|
+
end
|
495
|
+
|
496
|
+
teardown do
|
497
|
+
TestData.rollback(:after_data_truncate)
|
498
|
+
end
|
499
|
+
when :test_data
|
500
|
+
setup do
|
501
|
+
TestData.load
|
502
|
+
end
|
503
|
+
|
504
|
+
teardown do
|
505
|
+
TestData.rollback
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
```
|
511
|
+
|
512
|
+
And then (without any class inheritance complications), simply declare which
|
513
|
+
kind of test you're specifying:
|
514
|
+
|
515
|
+
```ruby
|
516
|
+
class SomeFactoryUsingTest < ActiveSupport::TestCase
|
517
|
+
test_data_mode :factory_bot
|
518
|
+
|
519
|
+
# … tests go here
|
520
|
+
end
|
521
|
+
|
522
|
+
class SomeTestDataUsingTest < ActionDispatch::IntegrationTest
|
523
|
+
test_data_mode :test_data
|
524
|
+
|
525
|
+
# etc.
|
526
|
+
end
|
527
|
+
```
|
528
|
+
|
529
|
+
By following an approach like this one, your `test_data` tests won't even see
|
530
|
+
your `create_*` factory methods and your `factory_bot` tests won't have access
|
531
|
+
to any of your `test_data`, either. From there, you can migrate tests onto
|
532
|
+
`test_data` incrementally, secure in the knowledge that you're not inadvertently
|
533
|
+
tangling your tests' dependency graph further.
|
534
|
+
|
535
|
+
#### Speeding up your test suite when using factories
|
536
|
+
|
537
|
+
##### Addressing redundant data cleanup
|
538
|
+
|
539
|
+
After adding `test_data` to your test suite, consider is how database cleanup
|
540
|
+
was being handled previously to make sure it isn't unnecessarily truncating
|
541
|
+
everything or resetting the transaction between tests. It's possible that your
|
542
|
+
suite is relying on Rails' built-in `use_transactional_tests` feature to wrap
|
543
|
+
your tests in always-rolled-back transactions, even if you're not using
|
544
|
+
fixtures. Or perhaps your suite uses
|
545
|
+
[database_cleaner](https://github.com/DatabaseCleaner/database_cleaner) to
|
546
|
+
truncate the database before or after each test. In either case, it's important
|
547
|
+
to know that by default [TestData.load](#testdataload) and
|
548
|
+
[TestData.rollback](#testdatarollback) will start and rollback a nested
|
549
|
+
transaction, respectively. That means—so long as they're called at the top of a
|
550
|
+
before-each hook and the end of an after-each hook—you might be able to disable
|
551
|
+
`use_transactional_tests` or remove your dependency on `database_cleaner` or any
|
552
|
+
other custom truncation logic you might have. Even if you get your suite running
|
553
|
+
immediately after adding `test_data`, it's still worth taking the time to
|
554
|
+
understand what's going on during test setup & teardown, because there may be an
|
555
|
+
opportunity to make your tests faster and more comprehensible by eliminating
|
556
|
+
redundant clean-up steps.
|
557
|
+
|
558
|
+
##### Avoiding truncate rollback churn
|
559
|
+
|
560
|
+
It's important to know that if your test suite has a mix of tests that call
|
561
|
+
[TestData.load](#testdataload) and tests that call
|
562
|
+
[TestData.truncate](#testdatatruncate), each time the test runner switches
|
563
|
+
between the two types, each call to `TestData.load` will cause the transaction
|
564
|
+
state to be rolled back from
|
565
|
+
[:after_data_truncate](#rolling-back-to-after-test-data-was-truncated) to
|
566
|
+
[:after_data_load](#rolling-back-to-after-the-data-was-loaded), only for the
|
567
|
+
next test to call `TestData.truncate` truncates all the tables again. In
|
568
|
+
practice, this shouldn't be too costly an operation, but if your test order is
|
569
|
+
randomized you might find that your build will run faster if you separate each
|
570
|
+
set of tests at runtime.
|
571
|
+
|
572
|
+
Separating your `test_data` and `factory_bot` tests is pretty trivial if you're
|
573
|
+
using RSpec, as the
|
574
|
+
[tag](https://relishapp.com/rspec/rspec-core/v/3-10/docs/command-line/tag-option)
|
575
|
+
feature was built with this sort of need in mind. Otherwise, you might consider
|
576
|
+
organizing the tests in different directories and running multiple commands to
|
577
|
+
execute them (e.g. `bin/rails test test/test_data_tests` and `bin/rails
|
578
|
+
test/factory_tests`). Every CI configuration is different, however, and you may
|
579
|
+
find yourself needing to get creative in configuring things to achieve the
|
580
|
+
fastest build time.
|
581
|
+
|
582
|
+
### Using `test_data` with Rails fixtures
|
583
|
+
|
584
|
+
While [Rails
|
585
|
+
fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
|
586
|
+
are similar to factories, the fact that they're run globally by Rails and
|
587
|
+
permanently committed to the test database actually makes them a little trickier
|
588
|
+
to work with. This section will cover a couple approaches for integrating
|
589
|
+
`test_data` into suites that use fixtures.
|
590
|
+
|
591
|
+
#### Getting your fixtures-dependent tests passing with `test_data`
|
592
|
+
|
593
|
+
It's more likely than not that all your tests will explode in dramatic fashion
|
594
|
+
as soon as you add `TestData.load` to a `setup` or `before(:each)` hook. Because
|
595
|
+
fixtures will be loaded all-at-once then your `test_data` dump will be inserted
|
596
|
+
directly on top of them. If everything works, or if you only encounter a few
|
597
|
+
errors throughout your test suite (perhaps based on assertions of the `count` of
|
598
|
+
a particular model), congratulations! You should still consider mitigating the
|
599
|
+
risks of coupling your tests to both data sources ([as discussed
|
600
|
+
above](#separating-your-test_data-and-factory-tests)) by migrating completely
|
601
|
+
onto `test_data` over time, but no further action is necessary or recommended.
|
602
|
+
|
603
|
+
If, however, you find yourself running into non-trivial challenges (like rampant
|
604
|
+
validation or constraint errors), `test_data` provides an API that **overrides
|
605
|
+
Rails' built-in fixtures behavior with a monkey patch**. If that bold text
|
606
|
+
warning wasn't enough to scare you from reading on, here's how to do it.
|
607
|
+
|
608
|
+
_[Note that the following requires `use_transactional_data_loader` to be enabled
|
609
|
+
in your [config](#testdataconfig), because it depends on transaction
|
610
|
+
rollbacks.]_
|
611
|
+
|
612
|
+
Here's what you can do if you can't get your fixtures to play nicely with your
|
613
|
+
`test_data` dump:
|
614
|
+
|
615
|
+
1. Near the top of your test helper, call:
|
616
|
+
[TestData.prevent_rails_fixtures_from_loading_automatically!](#testdataprevent_rails_fixtures_from_loading_automatically)
|
617
|
+
This will effectively turn
|
618
|
+
[setup_fixtures](https://github.com/rails/rails/blob/main/activerecord/lib/active_record/test_fixtures.rb#L105)
|
619
|
+
into a no-op, which means that your test fixtures will not be automatically
|
620
|
+
loaded into your test database
|
621
|
+
|
622
|
+
2. In tests that rely on your `test_data` dump, call [TestData.load and
|
623
|
+
TestData.rollback](#step-4-load-your-data-in-your-tests) as you normally
|
624
|
+
would. Because your fixtures won't be loaded automatically, they won't be
|
625
|
+
available to these tests
|
626
|
+
|
627
|
+
3. In tests that need fixtures, call
|
628
|
+
[TestData.load_rails_fixtures](#testdataload_rails_fixtures)
|
629
|
+
in a before-each hook and
|
630
|
+
[TestData.rollback(:after_load_rails_fixtures)](#rolling-back-to-after-rails-fixtures-were-loaded)
|
631
|
+
in an after-each hook. This will (in an almost comic level of
|
632
|
+
transaction-nesting) ensure your `test_data` dump is loaded in an initial
|
633
|
+
transaction, then ensure that it is truncated in a second transaction, before
|
634
|
+
loading your rails fixtures in a third transaction. These tests will have
|
635
|
+
access to all your fixture data without being tainted by any of your
|
636
|
+
`test_data` data
|
637
|
+
|
638
|
+
For example, you might add the following to an existing fixtures-dependent
|
639
|
+
test to get it passing:
|
640
|
+
|
641
|
+
```ruby
|
642
|
+
class AnExistingFixtureUsingTest < ActiveSupport::Testcase
|
643
|
+
def setup
|
644
|
+
TestData.load_rails_fixtures
|
645
|
+
# pre-existing setup
|
646
|
+
end
|
647
|
+
|
648
|
+
def test_stuff
|
649
|
+
#… etc
|
650
|
+
end
|
651
|
+
|
652
|
+
def teardown
|
653
|
+
TestData.rollback(:after_load_rails_fixtures)
|
654
|
+
end
|
655
|
+
end
|
656
|
+
```
|
657
|
+
|
658
|
+
_[You don't need to worry about whether `TestData.load` has been called
|
659
|
+
previously, the loader will infer your intent and ensure that the transaction
|
660
|
+
state is correct before loading your fixtures.]_
|
661
|
+
|
662
|
+
#### Separating your `test_data` and fixture tests
|
663
|
+
|
664
|
+
*This only applies if you had to use
|
665
|
+
[TestData.load_rails_fixtures](#testdataload_rails_fixtures) as shown above.*
|
666
|
+
|
667
|
+
Just [like with factories](#separating-your-test_data-and-factory-tests), you
|
668
|
+
might benefit from a test helper to clearly declare whether a test uses fixtures
|
669
|
+
or `test_data` right at the top. Following the same pattern, you might do this:
|
670
|
+
|
671
|
+
```ruby
|
672
|
+
class ActiveSupport::TestCase
|
673
|
+
def self.test_data_mode(mode)
|
674
|
+
case mode
|
675
|
+
when :fixtures
|
676
|
+
fixtures :all
|
677
|
+
|
678
|
+
setup do
|
679
|
+
TestData.load_rails_fixtures
|
680
|
+
end
|
681
|
+
|
682
|
+
teardown do
|
683
|
+
TestData.rollback(:after_load_rails_fixtures)
|
684
|
+
end
|
685
|
+
when :test_data
|
686
|
+
setup do
|
687
|
+
TestData.load
|
688
|
+
end
|
689
|
+
|
690
|
+
teardown do
|
691
|
+
TestData.rollback
|
692
|
+
end
|
693
|
+
end
|
694
|
+
end
|
695
|
+
end
|
696
|
+
```
|
697
|
+
|
698
|
+
Which would allow you to simplify the above fixtures-using test to:
|
699
|
+
|
700
|
+
```ruby
|
701
|
+
class AnExistingFixtureUsingTest < ActiveSupport::Testcase
|
702
|
+
test_data_mode :fixtures
|
703
|
+
|
704
|
+
def test_stuff
|
705
|
+
#… etc
|
706
|
+
end
|
707
|
+
end
|
708
|
+
```
|
709
|
+
|
710
|
+
#### Improving test suite speed with fixtures
|
711
|
+
|
712
|
+
Again, as is [the case with
|
713
|
+
factories](#improving-test-suite-speed-with-factories), every time your test
|
714
|
+
runner randomly picks a `test_data` test after running a fixtures-dependent
|
715
|
+
test, it will roll back your fixtures and the truncation of your `test_data`,
|
716
|
+
only to re-truncate your `test_data` data and reload your fixtures for the next
|
717
|
+
test that happens to use fixtures. But unlike truncation alone, loading your
|
718
|
+
fixtures is a non-trivial operation that can chew up a some serious time as your
|
719
|
+
suite runs.
|
720
|
+
|
721
|
+
As a result, we strongly encourage breaking up your test suite to avoid this
|
722
|
+
churn, even if it means splitting your test run over multiple CLI commands. If
|
723
|
+
you're using the Rails test runner and Minitest, that likely means sequestering
|
724
|
+
one set of tests to one directory and the other to a different directory, as
|
725
|
+
there is no granular control over to how the runner randomizes suites. And for
|
726
|
+
RSpec,
|
727
|
+
[tagging](https://relishapp.com/rspec/rspec-core/v/3-10/docs/command-line/tag-option)
|
728
|
+
each spec and running separate commands for each tag could yield significant
|
729
|
+
performance improvements.
|
730
|
+
|
312
731
|
## Rake Task Reference
|
313
732
|
|
314
733
|
### test_data:install
|
@@ -326,23 +745,43 @@ This task runs several generators:
|
|
326
745
|
too! This gem adds a new `test_data` environment and database that's intended
|
327
746
|
to be used to create and dump your test data. This new environment file loads
|
328
747
|
your `development` environment's configuration and disables migration schema
|
329
|
-
dumps so that you can run migrations
|
748
|
+
dumps so that you can run migrations against your `test_data` database without
|
330
749
|
affecting your app's `schema.rb` or `structure.sql`.
|
331
750
|
|
332
|
-
* `config/initializers/test_data.rb` -
|
333
|
-
with an empty block and comments
|
334
|
-
and their default values
|
751
|
+
* `config/initializers/test_data.rb` - Creates an initializer for the gem that
|
752
|
+
calls [TestData.config](#testdataconfig) with an empty block and comments
|
753
|
+
documenting the currently-available options and their default values
|
335
754
|
|
336
755
|
* `config/database.yml` - This generator adds a new `test_data` section to your
|
337
756
|
database configuration, named with the same scheme as your other databases
|
338
757
|
(e.g. `your_app_test_data`). If your configuration resembles Rails' generated
|
339
|
-
database.yml and has a working `&default` alias, then this should "just
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
defines
|
758
|
+
`database.yml` and has a working `&default` alias, then this should "just
|
759
|
+
work"
|
760
|
+
|
761
|
+
* `config/webpacker.yml` - The gem has nothing to do with web assets, but
|
762
|
+
[webpacker](https://github.com/rails/webpacker) will display some prominent
|
763
|
+
warnings or errors if it is loaded without a configuration entry for the
|
764
|
+
currently-running environment, so this generator defines an alias based on
|
765
|
+
your `development` config and then defines `test_data` as extending it
|
766
|
+
|
767
|
+
* `config/secrets.yml` - If your app still uses (the now-deprecated)
|
768
|
+
[secrets.yml](https://guides.rubyonrails.org/4_1_release_notes.html#config-secrets-yml)
|
769
|
+
file introduced in Rails 4.1, this generator will ensure that the `test_data`
|
770
|
+
environment is accounted for with a generated `secret_key_base` value. If you
|
771
|
+
have numerous secrets in this file's `development:` stanza, you may want to
|
772
|
+
alias and inherit it into `test_data:` like the `webpacker.yml` generator does
|
773
|
+
|
774
|
+
* `config/cable.yml` - In the absences of a configuration stanza,
|
775
|
+
[ActionCable](https://guides.rubyonrails.org/action_cable_overview.html) will
|
776
|
+
assume you're using Redis for tracking Websocket connections, so this
|
777
|
+
generator explicitly specifies `async` instead, since that's the default for
|
778
|
+
`development:`
|
779
|
+
|
780
|
+
### test_data:verify_config
|
781
|
+
|
782
|
+
This task will verify that your configuration appears to be valid by checking
|
783
|
+
with each of the gem's generators to inspect your configuration files, and will
|
784
|
+
error whenever a configuration problem is detected.
|
346
785
|
|
347
786
|
### test_data:initialize
|
348
787
|
|
@@ -353,22 +792,23 @@ your seed file. Specifically:
|
|
353
792
|
1. Creates the `test_data` environment's database, if it doesn't already exist
|
354
793
|
|
355
794
|
2. Ensures the database is non-empty to preserve data integrity (run
|
356
|
-
|
795
|
+
[test_data:drop_database](#test_datadrop_database) first if it contains
|
796
|
+
outdated test data)
|
357
797
|
|
358
798
|
3. Checks to see if a dump of the database already exists (by default, stored in
|
359
799
|
`test/support/test_data/`)
|
360
800
|
|
361
|
-
* If dumps do exist, it invokes
|
362
|
-
database
|
801
|
+
* If dumps do exist, it invokes [test_data:load](#test_dataload) to load
|
802
|
+
them into the database
|
363
803
|
|
364
804
|
* Otherwise, it invokes the task `db:schema:load` and `db:seed` (similar to
|
365
|
-
|
805
|
+
Rails' built-in `db:setup` task)
|
366
806
|
|
367
807
|
### test_data:dump
|
368
808
|
|
369
809
|
This task is designed to be run after you've created or updated your test data
|
370
|
-
and you
|
371
|
-
from your `test_data` environment's database:
|
810
|
+
and you're ready to run your tests against it. The task creates several plain
|
811
|
+
SQL dumps from your `test_data` environment's database:
|
372
812
|
|
373
813
|
* A schema-only dump, by default in `test/support/test_data/schema.sql`
|
374
814
|
|
@@ -389,7 +829,7 @@ options to control which tables are exported into which group.
|
|
389
829
|
This task will load your SQL dumps into your `test_data` database by:
|
390
830
|
|
391
831
|
1. Verifying the `test_data` environment's database is empty (creating it if it
|
392
|
-
doesn't exist)
|
832
|
+
doesn't exist and failing if it's not empty)
|
393
833
|
|
394
834
|
2. Verifying that your schema, test data, and non-test data SQL dumps can be
|
395
835
|
found at the configured paths
|
@@ -409,8 +849,10 @@ $ bin/rake test_data:dump
|
|
409
849
|
### test_data:create_database
|
410
850
|
|
411
851
|
This task will create the `test_data` environment's database if it does not
|
412
|
-
already exist. It also
|
413
|
-
|
852
|
+
already exist. It also
|
853
|
+
[enhances](https://dev.to/molly/rake-task-enhance-method-explained-3bo0) Rails'
|
854
|
+
`db:create` task so that `test_data` is created along with `development` and
|
855
|
+
`test`.
|
414
856
|
|
415
857
|
### test_data:drop_database
|
416
858
|
|
@@ -449,6 +891,12 @@ TestData.config do |config|
|
|
449
891
|
# `data_dump_path` will be truncated
|
450
892
|
# config.truncate_these_test_data_tables = nil
|
451
893
|
|
894
|
+
# Perform TestData.load and TestData.truncate inside nested
|
895
|
+
# transactions for increased test isolation and speed. Setting this
|
896
|
+
# to false will disable several features that depend on transactions
|
897
|
+
# being used
|
898
|
+
# config.use_transactional_data_loader = true
|
899
|
+
|
452
900
|
# Log level (valid values: [:debug, :info, :warn, :error, :quiet])
|
453
901
|
# Can also be set with env var TEST_DATA_LOG_LEVEL
|
454
902
|
# config.log_level = :info
|
@@ -468,7 +916,7 @@ savepoints](https://www.postgresql.org/docs/current/sql-savepoint.html)). By
|
|
468
916
|
default, data is loaded in a transaction and intended to be rolled back to the
|
469
917
|
point _immediately after_ the data was imported after each test. This way, your
|
470
918
|
test suite only pays the cost of importing the SQL file once, but each of your
|
471
|
-
tests can enjoy a clean slate free of
|
919
|
+
tests can enjoy a clean slate that's free of data pollution from other tests.
|
472
920
|
(This is similar to, but separate from, Rails fixtures'
|
473
921
|
[use_transactional_tests](https://edgeguides.rubyonrails.org/testing.html#testing-parallel-transactions)
|
474
922
|
option.)
|
@@ -477,22 +925,24 @@ To help think through the method's behavior, the method nicknames its
|
|
477
925
|
transactions `:before_data_load` and `:after_data_load`. The first time you call
|
478
926
|
`TestData.load`:
|
479
927
|
|
480
|
-
1.
|
928
|
+
1. Creates the `:before_data_load` savepoint
|
481
929
|
2. Executes the SQL found in the data dump (e.g.
|
482
930
|
`test/support/test_data/data.sql`) to insert your test data
|
483
|
-
3.
|
931
|
+
3. Creates the `:after_data_load` savepoint
|
484
932
|
|
485
933
|
If the method is called and the `:after_data_load` savepoint is already active
|
486
934
|
(indicating that the data is loaded), the method rolls back to
|
487
935
|
`:after_data_load`, inferring that the user's intention is to have a clean load
|
488
936
|
of the test data.
|
489
937
|
|
490
|
-
|
938
|
+
As an additional safeguard, in case a rollback is triggered unexpectedly (i.e.
|
491
939
|
calling `rollback_transaction` on `ActiveRecord::Base.connection` instead of via
|
492
|
-
`TestData.rollback`), `test_data` writes a memo that the data is
|
493
|
-
`ar_internal_metadata`. `TestData.load` uses this memo to detect this
|
494
|
-
will recreate the `:after_data_load` savepoint rather than attempt to
|
495
|
-
erroneously reload your SQL data dump.
|
940
|
+
`TestData.rollback`), `test_data` writes a memo indicating that the data is
|
941
|
+
loaded in `ar_internal_metadata`. `TestData.load` uses this memo to detect this
|
942
|
+
issue and will recreate the `:after_data_load` savepoint rather than attempt to
|
943
|
+
erroneously reload your SQL data dump. (Similar error-handling is built-into
|
944
|
+
[TestData.truncate](#testdatatruncate) and
|
945
|
+
[TestData.load_rails_fixtures](#testdataload_rails_fixtures), as well.)
|
496
946
|
|
497
947
|
#### Loading without transactions
|
498
948
|
|
@@ -501,15 +951,15 @@ strategy, both because it's faster and because it reduces the risk of test
|
|
501
951
|
pollution. However, you may need to commit your test data if the data needs to
|
502
952
|
be loaded by multiple processes or over multiple connections.
|
503
953
|
|
504
|
-
If you need to load the test data and commit it to the database, simply
|
505
|
-
`TestData.
|
954
|
+
If you need to load the test data and commit it to the database, simply set
|
955
|
+
`TestData.config.use_transactional_data_loader = false`.
|
506
956
|
|
507
|
-
|
508
|
-
|
957
|
+
If transactions are disabled, you'll need to decide whether and how to clear the
|
958
|
+
data out after each test. Many folks use
|
509
959
|
[database_cleaner](https://github.com/DatabaseCleaner/database_cleaner) for
|
510
|
-
this, while
|
960
|
+
this, while `test_data` offers a rudimentary
|
511
961
|
[TestData.truncate](https://github.com/testdouble/test_data#testdatatruncate)
|
512
|
-
method that
|
962
|
+
method that may be sufficient for your needs.
|
513
963
|
|
514
964
|
You might imagine something like this if you were loading the data just once for
|
515
965
|
the full run of a test suite:
|
@@ -517,38 +967,39 @@ the full run of a test suite:
|
|
517
967
|
```ruby
|
518
968
|
RSpec.configure do |config|
|
519
969
|
config.before :all do
|
520
|
-
TestData.load
|
970
|
+
TestData.load
|
521
971
|
end
|
522
972
|
|
523
973
|
config.after :all do
|
524
|
-
TestData.truncate
|
974
|
+
TestData.truncate
|
525
975
|
end
|
526
976
|
end
|
527
977
|
```
|
528
978
|
|
529
|
-
Note that
|
530
|
-
detect whether the data is already loaded
|
531
|
-
which will almost certainly result in
|
979
|
+
Note that when `use_transactional_data_loader` is `false`, subsequent
|
980
|
+
`TestData.load` calls won't be able to detect whether the data is already loaded
|
981
|
+
and will try to re-insert the data, which will almost certainly result in
|
982
|
+
primary key conflicts.
|
532
983
|
|
533
984
|
### TestData.rollback
|
534
985
|
|
535
986
|
Because the gem loads your data in a transaction, it makes it easy to rollback
|
536
|
-
to any of its defined savepoints
|
537
|
-
`:after_data_truncate`). In most cases you'll want to roll back to
|
987
|
+
to any of its defined savepoints. In most cases you'll want to roll back to
|
538
988
|
`:after_data_load` after each test, and that's what `TestData.rollback` will do
|
539
|
-
when called without an argument.
|
540
|
-
|
989
|
+
when called without an argument. If the specified savepoint isn't active,
|
990
|
+
calling `rollback` is a no-op.
|
541
991
|
|
542
|
-
|
992
|
+
The gem may create up to four nested savepoints in a single transaction, and
|
993
|
+
this method allows you to rollback to any of them. They form the following
|
994
|
+
stack:
|
543
995
|
|
544
|
-
|
545
|
-
`
|
546
|
-
`:
|
547
|
-
|
548
|
-
|
996
|
+
* `:before_data_load` - Taken before loading your `test_data` dump
|
997
|
+
* `:after_data_load` - Taken after loading your `test_data` dump
|
998
|
+
* `:after_truncate` - Taken after your `test_data` is truncated
|
999
|
+
* `:after_load_rails_fixtures` - Taken after Rails fixtures are loaded via
|
1000
|
+
[TestData.load_rails_fixtures](#testdataload_rails_fixtures)
|
549
1001
|
|
550
|
-
|
551
|
-
a no-op.)
|
1002
|
+
More details on rolling back to each of the gem's savepoints follows below.
|
552
1003
|
|
553
1004
|
#### Rolling back to before test data was loaded
|
554
1005
|
|
@@ -558,13 +1009,10 @@ that depend on that data _not being there_, you probably want to call
|
|
558
1009
|
you can rewind to the moment just before your test data was loaded by calling
|
559
1010
|
`TestData.rollback(:before_data_load)`.
|
560
1011
|
|
561
|
-
|
562
|
-
a no-op.)
|
563
|
-
|
564
|
-
**⚠️ Warning:** Repeatedly loading and rolling back to `:before_data_load` is
|
1012
|
+
**⚠️ Warning⚠️** Repeatedly loading and rolling back to `:before_data_load` is
|
565
1013
|
expensive! If your test suite calls `TestData.rollback(:before_data_load)`
|
566
1014
|
multiple times, it's likely you're re-loading your (possibly large) SQL file of
|
567
|
-
test data more times than is necessary. Consider using
|
1015
|
+
test data many more times than is necessary. Consider using
|
568
1016
|
[TestData.truncate](#testdatatruncate) to achieve the same goal with faster
|
569
1017
|
performance. Failing that, it might be preferable to partition your test suite
|
570
1018
|
so that similar tests are run in separate groups (as opposed to in a fully
|
@@ -572,27 +1020,41 @@ random or arbitrary order) to avoid repeatedly thrashing between rollbacks and
|
|
572
1020
|
reloads. This partitioning could be accomplished by either configuring your test
|
573
1021
|
runner or by running separate test commands for each group of tests.
|
574
1022
|
|
1023
|
+
#### Rolling back to after the data was loaded
|
1024
|
+
|
1025
|
+
This is the way you're likely to call this method most often.
|
1026
|
+
|
1027
|
+
When `TestData.rollback` is passed no arguments or called more explicitly as
|
1028
|
+
`TestData.rollback(:after_data_load)`, the method will rollback to the
|
1029
|
+
`:after_data_load` transaction savepoint taken immediately after the SQL dump
|
1030
|
+
was loaded. As a result, it is intended to be run after each test (e.g. in an
|
1031
|
+
`after(:each)` or `teardown`), to undo any changes made by the test.
|
1032
|
+
|
575
1033
|
#### Rolling back to after test data was truncated
|
576
1034
|
|
577
1035
|
If some of your tests call [TestData.truncate](#testdatatruncate) to clear out
|
578
|
-
your test data after it's been loaded
|
579
|
-
|
580
|
-
|
581
|
-
|
1036
|
+
your test data after it's been loaded (as
|
1037
|
+
[described](#getting-your-factory-tests-passing-after-adding-test_data) when
|
1038
|
+
using `test_data` in conjunction with `factory_bot`), then you will likely want
|
1039
|
+
to run `TestData.rollback(:after_data_truncate)` after each of them. This will
|
1040
|
+
rewind your test database's state to when those tables were first
|
1041
|
+
truncated—effectively re-cleaning the slate for the next test.
|
1042
|
+
|
1043
|
+
#### Rolling back to after Rails fixtures were loaded
|
582
1044
|
|
583
|
-
|
584
|
-
|
1045
|
+
If you're using [TestData.load_rails_fixtures](#testdataload_rails_fixtures) in
|
1046
|
+
your test's before-each hook, you'll probably want to teardown that test by
|
1047
|
+
rolling back with `TestData.rollback(:after_load_rails_fixtures)` in an
|
1048
|
+
after-each hook, which will rewind to the point just after your Rails fixtures
|
1049
|
+
were loaded.
|
585
1050
|
|
586
1051
|
### TestData.truncate
|
587
1052
|
|
588
1053
|
Do you have some tests that _shouldn't_ access your test data? Or did some
|
589
|
-
existing tests started failing after `test_data` was added? If you want to
|
590
|
-
the state of your `test` database to support these tests, you
|
591
|
-
|
592
|
-
|
593
|
-
slow reloads of your test data SQL file. `TestData.truncate`, meanwhile,
|
594
|
-
truncates all the tables that `TestData.load` inserted into and then creates
|
595
|
-
a savepoint nicknamed `:after_data_truncate`.
|
1054
|
+
existing tests started failing after `test_data` was added? If you want to clear
|
1055
|
+
the state of your `test` database to support these tests, you can accomplish
|
1056
|
+
this with `TestData.truncate`. It truncates all the tables that `TestData.load`
|
1057
|
+
inserted into and then creates a savepoint named `:after_data_truncate`.
|
596
1058
|
|
597
1059
|
Most often, you'll want to call `TestData.truncate` before each test that
|
598
1060
|
should _not_ have access to your test data created with this gem. After each
|
@@ -611,28 +1073,54 @@ end
|
|
611
1073
|
```
|
612
1074
|
|
613
1075
|
By default, all tables for which there is an `INSERT INTO` statement in your
|
614
|
-
test data SQL dump will be truncated
|
615
|
-
|
616
|
-
|
1076
|
+
test data SQL dump will be truncated (and cascading to any tables with foreign
|
1077
|
+
keys pointing to those tables), but you can also explicitly specify which tables
|
1078
|
+
should be truncated yourself by setting the `truncate_these_test_data_tables`
|
1079
|
+
property on [TestData.config](#testdataconfig) to an array of table names.
|
617
1080
|
|
618
|
-
|
619
|
-
in:
|
1081
|
+
#### If you're not using transactions
|
620
1082
|
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
available
|
1083
|
+
Just [like TestData.load](#loading-without-transactions), you can call
|
1084
|
+
`TestData.truncate` when `use_transactional_data_loader` is `false` and it will
|
1085
|
+
commit the truncation.
|
625
1086
|
|
626
|
-
|
627
|
-
is rolled back outside the `TestData.rollback` method (e.g.
|
628
|
-
`ActiveRecord::Base.connection.rollback_transaction`), the method will first
|
629
|
-
check a memo written to `ar_internal_metadata` and recreate the
|
630
|
-
`:after_data_truncate` savepoint
|
1087
|
+
### TestData.prevent_rails_fixtures_from_loading_automatically!
|
631
1088
|
|
632
|
-
|
1089
|
+
Call this method before any tests have been loaded or executed by your test
|
1090
|
+
runner if you're planning to use
|
1091
|
+
[TestData.load_rails_fixtures](#testdataload_rails_fixtures) to load Rails
|
1092
|
+
fixtures into any of your tests. This method will disable the default behavior
|
1093
|
+
of loading your Rails fixtures into the test database as soon as the first test
|
1094
|
+
case with fixtures enabled is executed. (Inspect the [source for the
|
1095
|
+
patch](/lib/test_data/active_record_ext.rb) to make sure you're comfortable with
|
1096
|
+
what it's doing.)
|
633
1097
|
|
634
|
-
|
635
|
-
|
1098
|
+
### TestData.load_rails_fixtures
|
1099
|
+
|
1100
|
+
As described in this README's [fixture interop
|
1101
|
+
guide](#getting-your-fixtures-dependent-tests-passing-with-test_data),
|
1102
|
+
`TestData.load_rails_fixtures` will load your app's [Rails
|
1103
|
+
fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
|
1104
|
+
into an effectively empty test database inside a nested transaction.
|
1105
|
+
|
1106
|
+
Using this feature requires that you've:
|
1107
|
+
|
1108
|
+
1. Invoked
|
1109
|
+
[TestData.prevent_rails_fixtures_from_loading_automatically!](#testdataprevent_rails_fixtures_from_loading_automatically)
|
1110
|
+
2. Have `config.use_transactional_data_loader` set to true (the default) in your
|
1111
|
+
[config](#testdataconfig)
|
1112
|
+
|
1113
|
+
When you call this method, it will do the following:
|
1114
|
+
|
1115
|
+
1. Verify your `test_data` dump has been loaded (or else load it)
|
1116
|
+
2. Verify the loaded data has been truncated (or else truncate it)
|
1117
|
+
3. Load your Rails fixtures from their YAML source files into your test database
|
1118
|
+
4. Create a new savepoint in the nested transactions named
|
1119
|
+
`:after_load_rails_fixtures`
|
1120
|
+
|
1121
|
+
Once loaded, your tests will be able to use your test fixtures inside a
|
1122
|
+
transaction. At teardown-time, you can reset those fixtures by rolling back with
|
1123
|
+
[TestData.rollback(:after_load_rails_fixtures)](#rolling-back-to-after-rails-fixtures-were-loaded).
|
636
1124
|
|
637
1125
|
## Assumptions
|
638
1126
|
|
@@ -643,15 +1131,16 @@ yet. Here are some existing assumptions and limitations:
|
|
643
1131
|
|
644
1132
|
* You're using Rails 6 or higher
|
645
1133
|
|
646
|
-
* Your app does not
|
1134
|
+
* Your app does not require Rails' [multi-database
|
647
1135
|
support](https://guides.rubyonrails.org/active_record_multiple_databases.html)
|
1136
|
+
in order to be tested
|
648
1137
|
|
649
1138
|
* Your app has the binstubs `bin/rake` and `bin/rails` that Rails generates and
|
650
|
-
they work (you can regenerate them with `rails app:update:bin`)
|
1139
|
+
they work (protip: you can regenerate them with `rails app:update:bin`)
|
651
1140
|
|
652
1141
|
* Your `database.yml` defines a `&default` alias from which to extend the
|
653
|
-
`test_data` database configuration (if
|
654
|
-
database
|
1142
|
+
`test_data` database configuration (if your YAML file lacks one, you can
|
1143
|
+
always specify the `test_data` database configuration manually)
|
655
1144
|
|
656
1145
|
## Fears, Uncertainties, and Doubts
|
657
1146
|
|
@@ -672,7 +1161,7 @@ If you use `factory_bot` and all of these are true:
|
|
672
1161
|
menu
|
673
1162
|
|
674
1163
|
* Your default factories generate models that resemble real records created by
|
675
|
-
your production application, as opposed to
|
1164
|
+
your production application, as opposed to representing the
|
676
1165
|
sum-of-all-edge-cases with every boolean flag enabled and optional attribute
|
677
1166
|
set
|
678
1167
|
|
@@ -690,7 +1179,7 @@ designed to address. We hope you'll consider trying it with an open mind. At the
|
|
690
1179
|
same time, we acknowledge that large test suites can't be rewritten and migrated
|
691
1180
|
to a different source of test data overnight—nor should they be! See our notes
|
692
1181
|
on [migrating to `test_data`
|
693
|
-
incrementally](#
|
1182
|
+
incrementally](#factory--fixture-interoperability-guide)
|
694
1183
|
|
695
1184
|
### How will I handle merge conflicts in these SQL files if I have lots of people working on lots of feature branches all adding to the `test_data` database dumps?
|
696
1185
|
|
@@ -717,124 +1206,6 @@ iterate than detect bugs. Once you you have a reasonably stable feature working
|
|
717
1206
|
end-to-end, that's a good moment to start adding integration tests (and thus
|
718
1207
|
pulling in a test data gem like this one to help you).
|
719
1208
|
|
720
|
-
### We already have thousands of tests that depend on Rails fixtures or factory_bot; can we start using this gem without throwing them away and starting over?
|
721
|
-
|
722
|
-
Yes, `test_data` was written with this sort of incremental transition in mind!
|
723
|
-
|
724
|
-
Our strongest recommendation is to write each test against only a single source
|
725
|
-
of test data. Integration tests inevitably become coupled to the data that's
|
726
|
-
available to them, and if a test has access to fixtures, records created by a
|
727
|
-
factory, and a `test_data` SQL dump, it is likely to unintentionally become
|
728
|
-
dependent on all three. This could result in the test having more ways to fail
|
729
|
-
than necessary and make it harder to simplify your test data strategy later.
|
730
|
-
Instead, consider explicitly opting into a single type of test data for each
|
731
|
-
test.
|
732
|
-
|
733
|
-
The rest comes down to how you want to organize your tests, as discussed below.
|
734
|
-
|
735
|
-
#### Approach 1: test-data-specific test subclasses
|
736
|
-
|
737
|
-
If you're currently using `factory_bot`, you might already have something like
|
738
|
-
this in your `test_helper.rb` file:
|
739
|
-
|
740
|
-
```ruby
|
741
|
-
class ActiveSupport::TestCase
|
742
|
-
include FactoryBot::Syntax::Methods
|
743
|
-
end
|
744
|
-
```
|
745
|
-
|
746
|
-
To avoid including these methods with every Rails-aware test, you might consider
|
747
|
-
pushing down new classes for each source of test data:
|
748
|
-
|
749
|
-
```ruby
|
750
|
-
# Tests using data created by `test_data`
|
751
|
-
class TestDataTestCase < ActiveSupport::TestCase
|
752
|
-
def setup
|
753
|
-
TestData.load
|
754
|
-
end
|
755
|
-
|
756
|
-
def teardown
|
757
|
-
TestData.rollback
|
758
|
-
end
|
759
|
-
end
|
760
|
-
|
761
|
-
# Tests using data created by `factory_bot`
|
762
|
-
class FactoryBotTestCase < ActiveSupport::TestCase
|
763
|
-
include FactoryBot::Syntax::Methods
|
764
|
-
|
765
|
-
def setup
|
766
|
-
TestData.truncate
|
767
|
-
end
|
768
|
-
|
769
|
-
def teardown
|
770
|
-
TestData.rollback(:after_data_truncate)
|
771
|
-
end
|
772
|
-
end
|
773
|
-
```
|
774
|
-
|
775
|
-
From there, the class that each test extends will indicate which test data
|
776
|
-
strategy it uses.
|
777
|
-
|
778
|
-
This approach may work in simple cases, but won't be well-suited to if you're
|
779
|
-
already extending any of the half-dozen subclasses of `ActiveSupport::TestCase`
|
780
|
-
provided by Rails (or their analogues from
|
781
|
-
[rspec-rails](https://github.com/rspec/rspec-rails)).
|
782
|
-
|
783
|
-
#### Approach 2: write a helper method to set things up for you
|
784
|
-
|
785
|
-
Every situation will be different, but one strategy that suits a lot of
|
786
|
-
circumstances would be to write a method to declare and configure the test data
|
787
|
-
strategy for the current test.
|
788
|
-
|
789
|
-
Taking from [this
|
790
|
-
example](/example/test/integration/better_mode_switching_demo_test.rb) test, you
|
791
|
-
could implement a class method like this:
|
792
|
-
|
793
|
-
```ruby
|
794
|
-
class ActiveSupport::TestCase
|
795
|
-
def self.test_data_mode(mode)
|
796
|
-
case mode
|
797
|
-
when :factory_bot
|
798
|
-
require "factory_bot_rails"
|
799
|
-
include FactoryBot::Syntax::Methods
|
800
|
-
|
801
|
-
setup do
|
802
|
-
TestData.truncate
|
803
|
-
end
|
804
|
-
|
805
|
-
teardown do
|
806
|
-
TestData.rollback(:after_data_truncate)
|
807
|
-
end
|
808
|
-
when :test_data
|
809
|
-
setup do
|
810
|
-
TestData.load
|
811
|
-
end
|
812
|
-
|
813
|
-
teardown do
|
814
|
-
TestData.rollback
|
815
|
-
end
|
816
|
-
end
|
817
|
-
end
|
818
|
-
end
|
819
|
-
```
|
820
|
-
|
821
|
-
And then (without any class inheritance complications), simply declare which
|
822
|
-
kind of test you're specifying:
|
823
|
-
|
824
|
-
```ruby
|
825
|
-
class SomeFactoryUsingTest < ActiveSupport::TestCase
|
826
|
-
test_data_mode :factory_bot
|
827
|
-
|
828
|
-
# … tests go here
|
829
|
-
end
|
830
|
-
|
831
|
-
class SomeTestDataUsingTest < ActionDispatch::IntegrationTest
|
832
|
-
test_data_mode :test_data
|
833
|
-
|
834
|
-
# etc.
|
835
|
-
end
|
836
|
-
```
|
837
|
-
|
838
1209
|
### Why can't I save multiple database dumps to cover different scenarios?
|
839
1210
|
|
840
1211
|
For the same reason you (probably) don't have multiple production databases: the
|
@@ -854,7 +1225,8 @@ production itself.
|
|
854
1225
|
|
855
1226
|
### Are you sure I should commit these SQL dumps? They're way too big!
|
856
1227
|
|
857
|
-
If the dump files generated by `test_data:dump`
|
1228
|
+
If the dump files generated by `test_data:dump` seem massive, consider the
|
1229
|
+
cause:
|
858
1230
|
|
859
1231
|
1. If you inadvertently created more data than necessary, you might consider
|
860
1232
|
resetting (or rolling back) your changes and making another attempt at
|
@@ -867,7 +1239,9 @@ If the dump files generated by `test_data:dump` are absolutely massive, consider
|
|
867
1239
|
where they'd still be committed to git, but won't loaded by your tests
|
868
1240
|
|
869
1241
|
* Exclude data from those tables entirely by adding them to the
|
870
|
-
`config.dont_dump_these_tables` array
|
1242
|
+
`config.dont_dump_these_tables` array. (Note that `rake test_data:load`
|
1243
|
+
won't be able to restore these tables into your `test_data` environment,
|
1244
|
+
so if the data is needed for the app to operate, you'll need to dump them)
|
871
1245
|
|
872
1246
|
3. If the dumps are _necessarily_ really big (some apps are complex!), consider
|
873
1247
|
looking into [git-lfs](https://git-lfs.github.com) for tracking them without
|
@@ -903,7 +1277,7 @@ This test is simple, self-contained, clearly denotes
|
|
903
1277
|
[arrange-act-assert](https://github.com/testdouble/contributing-tests/wiki/Arrange-Act-Assert),
|
904
1278
|
and (most importantly) will only fail if the functionality stops working.
|
905
1279
|
Maximizing the number of tests that can be written expressively and succinctly
|
906
|
-
without the aid of
|
1280
|
+
without the aid of shared test data is a laudable goal that more teams should
|
907
1281
|
embrace.
|
908
1282
|
|
909
1283
|
However, what if the code you're writing doesn't need 3 records in the database,
|
@@ -913,8 +1287,10 @@ point, you have two options:
|
|
913
1287
|
|
914
1288
|
1. Critically validate your design: why is it so hard to set up? Does it
|
915
1289
|
_really_ require so much persisted data to exercise this behavior? Would a
|
916
|
-
plain old Ruby
|
917
|
-
|
1290
|
+
[plain old Ruby
|
1291
|
+
object](https://steveklabnik.com/writing/the-secret-to-rails-oo-design) that
|
1292
|
+
defined a pure function have been feasible? Could a model instance or even a
|
1293
|
+
`Struct` be passed to the
|
918
1294
|
[subject](https://github.com/testdouble/contributing-tests/wiki/Subject)
|
919
1295
|
instead of loading everything from the database? When automated testing is
|
920
1296
|
saved for the very end of a feature's development, it can feel too costly to
|
@@ -928,9 +1304,9 @@ point, you have two options:
|
|
928
1304
|
|
929
1305
|
As a result, there is no one-size-fits-all approach. Straightforward behavior
|
930
1306
|
that can be invoked with a clear, concise test has no reason to be coupled to a
|
931
|
-
shared source of test data. Subtle behavior that requires lots of
|
932
|
-
|
933
|
-
that data. So both kinds of test clearly have their place.
|
1307
|
+
shared source of test data. Subtle behavior that requires lots of
|
1308
|
+
carefully-arranged data would see its tests grow unwieldy without something to
|
1309
|
+
help populate that data. So both kinds of test clearly have their place.
|
934
1310
|
|
935
1311
|
But this is a pretty nuanced discussion that can be hard to keep in mind when
|
936
1312
|
under deadline pressure or on a large team where building consensus around norms
|
@@ -944,21 +1320,21 @@ integration tests, but not for basic tests of models, like so:
|
|
944
1320
|
|
945
1321
|
```ruby
|
946
1322
|
class ActionDispatch::IntegrationTest
|
947
|
-
|
1323
|
+
setup do
|
948
1324
|
TestData.load
|
949
1325
|
end
|
950
1326
|
|
951
|
-
|
1327
|
+
teardown do
|
952
1328
|
TestData.rollback
|
953
1329
|
end
|
954
1330
|
end
|
955
1331
|
|
956
1332
|
class ActiveSupport::TestCase
|
957
|
-
|
1333
|
+
setup do
|
958
1334
|
TestData.truncate
|
959
1335
|
end
|
960
1336
|
|
961
|
-
|
1337
|
+
teardown do
|
962
1338
|
TestData.rollback(:after_data_truncate)
|
963
1339
|
end
|
964
1340
|
end
|