test_data 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|