test_data 0.0.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +41 -0
  3. data/.standard.yml +2 -0
  4. data/CHANGELOG.md +43 -0
  5. data/Gemfile.lock +17 -15
  6. data/LICENSE.txt +1 -6
  7. data/README.md +1232 -17
  8. data/example/.gitignore +1 -4
  9. data/example/Gemfile +3 -0
  10. data/example/Gemfile.lock +100 -71
  11. data/example/README.md +2 -22
  12. data/example/config/application.rb +3 -0
  13. data/example/config/credentials.yml.enc +1 -1
  14. data/example/config/database.yml +2 -0
  15. data/example/spec/rails_helper.rb +64 -0
  16. data/example/spec/requests/boops_spec.rb +17 -0
  17. data/example/spec/requests/rails_fixtures_override_spec.rb +106 -0
  18. data/example/spec/spec_helper.rb +94 -0
  19. data/example/test/factories.rb +4 -0
  20. data/example/test/integration/better_mode_switching_demo_test.rb +41 -0
  21. data/example/test/integration/boops_that_boop_boops_test.rb +17 -0
  22. data/example/test/integration/dont_dump_tables_test.rb +7 -0
  23. data/example/test/integration/load_rollback_truncate_test.rb +190 -0
  24. data/example/test/integration/mode_switching_demo_test.rb +38 -0
  25. data/example/test/integration/parallel_boops_with_fixtures_test.rb +10 -0
  26. data/example/test/integration/parallel_boops_without_fixtures_test.rb +9 -0
  27. data/example/test/integration/rails_fixtures_double_load_test.rb +10 -0
  28. data/example/test/integration/rails_fixtures_override_test.rb +110 -0
  29. data/example/test/integration/test_data_hooks_test.rb +89 -0
  30. data/example/test/integration/transaction_committing_boops_test.rb +27 -0
  31. data/example/test/test_helper.rb +4 -31
  32. data/lib/generators/test_data/cable_yaml_generator.rb +18 -0
  33. data/lib/generators/test_data/database_yaml_generator.rb +3 -4
  34. data/lib/generators/test_data/environment_file_generator.rb +7 -14
  35. data/lib/generators/test_data/initializer_generator.rb +51 -0
  36. data/lib/generators/test_data/secrets_yaml_generator.rb +19 -0
  37. data/lib/generators/test_data/webpacker_yaml_generator.rb +4 -3
  38. data/lib/test_data.rb +42 -1
  39. data/lib/test_data/active_record_ext.rb +11 -0
  40. data/lib/test_data/config.rb +57 -4
  41. data/lib/test_data/configurators.rb +3 -0
  42. data/lib/test_data/configurators/cable_yaml.rb +25 -0
  43. data/lib/test_data/configurators/environment_file.rb +3 -2
  44. data/lib/test_data/configurators/initializer.rb +26 -0
  45. data/lib/test_data/configurators/secrets_yaml.rb +25 -0
  46. data/lib/test_data/configurators/webpacker_yaml.rb +4 -3
  47. data/lib/test_data/custom_loaders/abstract_base.rb +25 -0
  48. data/lib/test_data/custom_loaders/rails_fixtures.rb +42 -0
  49. data/lib/test_data/dumps_database.rb +55 -5
  50. data/lib/test_data/generator_support.rb +3 -0
  51. data/lib/test_data/inserts_test_data.rb +25 -0
  52. data/lib/test_data/loads_database_dumps.rb +8 -8
  53. data/lib/test_data/log.rb +76 -0
  54. data/lib/test_data/manager.rb +187 -0
  55. data/lib/test_data/rake.rb +20 -9
  56. data/lib/test_data/save_point.rb +34 -0
  57. data/lib/test_data/statistics.rb +31 -0
  58. data/lib/test_data/truncates_test_data.rb +31 -0
  59. data/lib/test_data/verifies_dumps_are_loadable.rb +4 -4
  60. data/lib/test_data/version.rb +1 -1
  61. data/script/reset_example_app +18 -0
  62. data/script/test +78 -13
  63. data/test_data.gemspec +1 -1
  64. metadata +36 -4
  65. data/lib/test_data/transactional_data_loader.rb +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3dafe4150b9a34a5b87c20af4a98704f03be77551ac4ee85d60ce73fce042d7
4
- data.tar.gz: d3bcc499c71f69a18fa421afe3e7d77afa03d2a353fd5a22d361f5114732a44d
3
+ metadata.gz: 84a9fc3fe7b3dda0cf1ebdc775c9191757d21de11e033189c6450b91f63332e7
4
+ data.tar.gz: 0a47179f0607d9c57f63706e35de176b14d93989c6e5406094524a0fb3b09704
5
5
  SHA512:
6
- metadata.gz: fcf3c41da800abc3cf14cc2ebf31550ee0ef19ee949555a129f5eda13e4901672bc92a3305979d639ea23c3985ee354f463f36d01587d33bc40d384bed43ac82
7
- data.tar.gz: e998f47e86ed7c6b2c74c11a202f45633b76a068b9702e80804d563d9d645a60a78312b688a1f38f579def8029107d06981ee5a39b258255f166d7cecd426a36
6
+ metadata.gz: 4c10de3f9e234ae53e47553d099612dc7474cb3e98022b6a953d60beb8da3f502b00f506f29729dad0a9eb37c8e7f05a662263963300d7c531f48fef660c9173
7
+ data.tar.gz: d718e34070ca15bd9d0e27c75789e170e42da183fac8efc973404d9cea909ce984453f9393277b37ad36ff42fa4866c66de14d2a82a149ae536f0555c2f5f52d
@@ -0,0 +1,41 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on: [push, pull_request, workflow_dispatch]
11
+
12
+ jobs:
13
+ test:
14
+
15
+ runs-on: ubuntu-latest
16
+
17
+ env:
18
+ PGHOST: "localhost"
19
+ PGPORT: "5432"
20
+
21
+ services:
22
+ postgres:
23
+ image: postgres:13
24
+ env:
25
+ POSTGRES_USER: "runner"
26
+ POSTGRES_HOST_AUTH_METHOD: trust
27
+ ports: ["5432:5432"]
28
+
29
+ strategy:
30
+ matrix:
31
+ ruby-version: ['2.7', '3.0']
32
+
33
+ steps:
34
+ - uses: actions/checkout@v2
35
+ - name: Set up Ruby
36
+ uses: ruby/setup-ruby@v1
37
+ with:
38
+ ruby-version: ${{ matrix.ruby-version }}
39
+ bundler-cache: true
40
+ - name: Run tests
41
+ run: script/test
data/.standard.yml ADDED
@@ -0,0 +1,2 @@
1
+ ruby_version: 2.4.0
2
+
data/CHANGELOG.md CHANGED
@@ -1,2 +1,45 @@
1
1
  # unreleased
2
2
 
3
+ - Adds several lifecycle hooks:
4
+ - config.after_test_data_load
5
+ - config.after_test_data_truncate
6
+ - config.after_rails_fixture_load
7
+
8
+ # 0.2.0
9
+
10
+ - BREAKING CHANGES: Remove or rename a bunch of APIs that aren't quite necessary
11
+ and leak too much implementation, requiring too much cognitive load for users.
12
+ - Remove config.use_transactional_data_loader
13
+ - Remove TestData.rollback
14
+ - Change TestData.load to TestData.uses_test_data and make it transaction-only
15
+ - Change TestData.truncate to TestData.uses_clean_slate and make it
16
+ transaction-only
17
+ - Change TestData.load_rails_fixtures to TestData.uses_rails_fixtures and make
18
+ it transaction-only
19
+ - Add TestData.insert_test_data_dump, which will blindly insert the test SQL
20
+ dump of test data without any transaction management
21
+ - [#2](https://github.com/testdouble/test_data/issues/2) - Work around
22
+ hard-coded environment names when initializing test_data environment secrets
23
+
24
+ # 0.1.0
25
+
26
+ - New feature: `TestData.load_rails_fixtures` to override default fixtures
27
+ behavior by loading it in a nested transaction after `TestData.truncate`
28
+ - Breaking change: move transactions configuration out of `TestData.load` and
29
+ instead a global setting for `TestData.config` named
30
+ `use_transactional_data_loader`
31
+ - Cascades truncation of test_data tables unless they're explicitly specified by
32
+ the truncate_these_test_data_tables` option
33
+ - Add secrets.yml and cable.yml generators to `test_data:configure` task
34
+ - Print the size of each dump and warn when dump size reaches certain thresholds
35
+ or increases significantly in the `test_data:dump` task
36
+
37
+ # 0.0.2
38
+
39
+ - Make the rest of the gem better
40
+ - Rename `TransactionData.load_data_dump` to `TransactionData.load`
41
+
42
+ # 0.0.1
43
+
44
+ - Make it work
45
+
data/Gemfile.lock CHANGED
@@ -1,26 +1,26 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- test_data (0.0.1)
4
+ test_data (0.2.1)
5
5
  railties (~> 6.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- actionpack (6.1.3.1)
11
- actionview (= 6.1.3.1)
12
- activesupport (= 6.1.3.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.3.1)
18
- activesupport (= 6.1.3.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.3.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,17 +29,19 @@ GEM
29
29
  ast (2.4.2)
30
30
  builder (3.2.4)
31
31
  coderay (1.1.3)
32
- concurrent-ruby (1.1.8)
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.9.1)
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.3)
41
42
  minitest (5.14.4)
42
- nokogiri (1.11.3-arm64-darwin)
43
+ nokogiri (1.11.7)
44
+ mini_portile2 (~> 2.5.0)
43
45
  racc (~> 1.4)
44
46
  parallel (1.20.1)
45
47
  parser (3.0.1.0)
@@ -56,11 +58,11 @@ GEM
56
58
  nokogiri (>= 1.6)
57
59
  rails-html-sanitizer (1.3.0)
58
60
  loofah (~> 2.3)
59
- railties (6.1.3.1)
60
- actionpack (= 6.1.3.1)
61
- activesupport (= 6.1.3.1)
61
+ railties (6.1.4)
62
+ actionpack (= 6.1.4)
63
+ activesupport (= 6.1.4)
62
64
  method_source
63
- rake (>= 0.8.7)
65
+ rake (>= 0.13)
64
66
  thor (~> 1.0)
65
67
  rainbow (3.0.0)
66
68
  rake (13.0.3)
@@ -91,7 +93,7 @@ GEM
91
93
  zeitwerk (2.4.2)
92
94
 
93
95
  PLATFORMS
94
- arm64-darwin-20
96
+ ruby
95
97
 
96
98
  DEPENDENCIES
97
99
  minitest
data/LICENSE.txt CHANGED
@@ -1,9 +1,4 @@
1
- Copyright (c) 2019 Test Double, LLC
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) 2021 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,35 +1,1250 @@
1
- # TestData
1
+ # The `test_data` gem
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/test_data`. To experiment with that code, run `bin/console` for an interactive prompt.
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.
4
5
 
5
- TODO: Delete this and the text above, and describe your gem
6
+ The gem serves as both an alternative to
7
+ [fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
8
+ & [factory_bot](https://github.com/thoughtbot/factory_bot), as well a broader
9
+ workflow for building test suites that will scale gracefully as your application
10
+ grows in size and complexity.
6
11
 
7
- ## Installation
12
+ What it does:
8
13
 
9
- Add this line to your application's Gemfile:
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**
20
+
21
+ * Exposes a simple API for ensuring that your data will be pristine for each of
22
+ your tests, whether the test depends on test_data, an empty database, or Rails
23
+ fixtures
24
+
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
28
+
29
+ If you've despaired over the seeming inevitability that all Rails test suites
30
+ will eventually grow to become slow, flaky, and incomprehensible, then this gem
31
+ is for you! And even if you're [a factory_bot
32
+ fan](https://twitter.com/searls/status/1379491813099253762?s=20), we hope you'll
33
+ be open to the idea that [there might be a better way](
34
+ #but-we-use-and-like-factory_bot-and-so-i-am-inclined-to-dislike-everything-about-this-gem).
35
+
36
+ _[Full disclosure: because the gem is still brand new, it makes a number of
37
+ [assumptions](#assumptions)—chief among them being that **Postgres & Rails 6+
38
+ are required**—so it may not work for every project just yet.]_
39
+
40
+ ## Documentation
41
+
42
+ This gem requires a lot of documentation—not because `test_data` does a lot of
43
+ things, but because managing one's test data is an inherently complex task. If
44
+ one reason Rails apps chronically suffer from slow tests is that other
45
+ approaches oversimplify test data management, it stands to reason that any
46
+ discomfort caused by `test_data`'s scope may not be _unnecessary complexity_ but
47
+ instead be an indication of how little of the problem's _essential complexity_
48
+ we have reckoned with to this point.
49
+
50
+ 1. [Getting Started Guide](#getting-started-guide)
51
+ 1. [Install and initialize `test_data`](#step-1-install-and-initialize-test_data)
52
+ 2. [Create some test data](#step-2-create-some-test-data)
53
+ 3. [Dump your `test_data` database](#step-3-dump-your-test_data-database)
54
+ 4. [Load your data in your tests](#step-4-load-your-data-in-your-tests)
55
+ 5. [Keeping your test data up-to-date](#step-5-keeping-your-test-data-up-to-date)
56
+ 2. [Factory & Fixture Interoperability Guide](#factory--fixture-interoperability-guide)
57
+ * [Using `test_data` with `factory_bot`](#using-test_data-with-factory_bot)
58
+ * [Using `test_data` with Rails fixtures](#using-test_data-with-rails-fixtures)
59
+ 3. [Rake Task Reference](#rake-task-reference)
60
+ * [test_data:install](#test_datainstall)
61
+ * [test_data:configure](#test_dataconfigure)
62
+ * [test_data:verify_config](#test_dataverify_config)
63
+ * [test_data:initialize](#test_datainitialize)
64
+ * [test_data:dump](#test_datadump)
65
+ * [test_data:load](#test_dataload)
66
+ * [test_data:create_database](#test_datacreate_database)
67
+ * [test_data:drop_database](#test_datadrop_database)
68
+ 4. [API Reference](#api-reference)
69
+ * [TestData.uses_test_data](#testdatauses_test_data)
70
+ * [TestData.uses_clean_slate](#testdatauses_clean_slate)
71
+ * [TestData.uses_rails_fixtures(self)](#testdatauses_rails_fixtures)
72
+ * [TestData.prevent_rails_fixtures_from_loading_automatically!](#testdataprevent_rails_fixtures_from_loading_automatically)
73
+ * [TestData.config](#testdataconfig)
74
+ * [TestData.insert_test_data_dump](#testdatainsert_test_data_dump)
75
+ 5. [Assumptions](#assumptions)
76
+ 6. [Fears, Uncertainties, and Doubts](#fears-uncertainties-and-doubts) (Q & A)
77
+ * [But we're already happy with
78
+ factory_bot!](#but-we-use-and-like-factory_bot-and-so-i-am-inclined-to-dislike-everything-about-this-gem)
79
+ * [How will we handle merge conflicts in the schema
80
+ dumps?](#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)
81
+ * [Why can't I manage different SQL dumps for different
82
+ scenarios?](#why-cant-i-save-multiple-database-dumps-to-cover-different-scenarios)
83
+ * [These SQL dumps are way too large to commit to
84
+ git!](#are-you-sure-i-should-commit-these-sql-dumps-theyre-way-too-big)
85
+ * [Tests shouldn't rely on shared test data if they don't need
86
+ to](#tests-shouldnt-use-shared-test-data-they-should-instantiate-the-objects-they-need)
87
+ * [My tests aren't as fast as they should
88
+ be](#im-worried-my-tests-arent-as-fast-as-they-should-be)
89
+ 7. [Code of Conduct](#code-of-conduct)
90
+ 8. [Changelog](/CHANGELOG.md)
91
+ 9. [MIT License](/LICENSE.txt)
92
+
93
+ ## Getting started guide
94
+
95
+ This guide will walk you through setting up `test_data` in your application. You
96
+ might notice that it's more complicated than installing a gem and declaring some
97
+ default `Widget` attributes! The hard truth is that designing robust and
98
+ reliable test data is an inherently complex problem and takes some thoughtful
99
+ planning. There are plenty of shortcuts available, but experience has shown they
100
+ tend to collapse under their own weight as your app scales and your team
101
+ grows—exactly when having a suite of fast & reliable tests is most valuable.
102
+
103
+ And if you get stuck or need help as you're getting started, please feel free to
104
+ [ask us for help](https://github.com/testdouble/test_data/discussions/new)!
105
+
106
+ ### Step 1: Install and initialize `test_data`
107
+
108
+ #### Adding the gem
109
+
110
+ First, add `test_data` to your Gemfile. Either include it in all groups or add
111
+ it to the `:development`, `:test`, and (the all new!) `:test_data` gem groups:
112
+
113
+ ```ruby
114
+ group :development, :test, :test_data do
115
+ gem "test_data"
116
+ # … other gems available to development & test
117
+ end
118
+ ```
119
+
120
+ Since the `test_data` environment is designed to be used similarly to
121
+ `development` (i.e. with a running server and interacting via a browser), any
122
+ gems in your `:development` gem group should likely be included in a
123
+ `:test_data` gem group as well.
124
+
125
+ #### Configuring the gem and initializing the database
126
+
127
+ The gem ships with a number of Rake tasks, including
128
+ [test_data:install](#test_datainstall), which will generate the necessary
129
+ configuration and initialize a `test_data` database:
130
+
131
+ ```
132
+ $ bin/rake test_data:install
133
+ ```
134
+
135
+ This should output something like:
136
+
137
+ ```
138
+ create config/environments/test_data.rb
139
+ create config/initializers/test_data.rb
140
+ insert config/database.yml
141
+ insert config/webpacker.yml
142
+ insert config/webpacker.yml
143
+ Created database 'yourappname_test_data'
144
+ set_config
145
+ ------------
146
+
147
+ (1 row)
148
+
149
+ Your test_data environment and database are ready for use! You can now run
150
+ your server (or any command) to create some test data like so:
151
+
152
+ $ RAILS_ENV=test_data bin/rails server
153
+
154
+ ````
155
+
156
+ The purpose of the `test_data` database is to provide a sandbox in which you
157
+ will manually generate test data by playing around with your app. Rather than
158
+ try to imitate realistic data using factories and fixtures (a task which only
159
+ grows more difficult as your models and their associations increase in
160
+ complexity), your test data will always be realistic because your real
161
+ application will have created it!
162
+
163
+ ### Step 2: Create some test data
164
+
165
+ Now comes the fun part! It's time to start up your server in the new environment
166
+ and create some records by interacting with your system.
167
+
168
+ #### Running the server (and other commands)
169
+
170
+ To run your server against the new `test_data` database, set the `RAILS_ENV`
171
+ environment variable:
172
+
173
+ ```
174
+ $ RAILS_ENV=test_data bin/rails server
175
+ ```
176
+
177
+ _[If you're using [webpacker](https://github.com/rails/webpacker), you may also
178
+ need to start its development server as well with `RAILS_ENV=test_data
179
+ bin/webpack-dev-server`]_
180
+
181
+ Because `test_data` creates a full-fledged Rails environment, you can run any
182
+ number of Rails commands or Rake tasks against its database by setting
183
+ `RAILS_ENV=test_data`, either in your shell environment or with each command
184
+ (e.g. `RAILS_ENV=test_data bin/rake db:migrate`)
185
+
186
+ _[Aside: If you experience any hiccups in getting your server to work, please
187
+ [open an issue](https://github.com/testdouble/test_data/issues/new) and let us
188
+ know—it may present an opportunity for us to improve the `test_data:configure`
189
+ task!]_
190
+
191
+ #### Create test data by using your app
192
+
193
+ Once the app is running, it's time to generate some test data. You'll know how
194
+ to accomplish this step better than anyone—it's your app, after all!
195
+
196
+ A few bits of advice click & type some test data into existence:
197
+
198
+ * Spend a little time thoughtfully navigating each feature of your app in order
199
+ to generate enough data to be representative of what would be needed to test
200
+ them (e.g. one `User` per role, one of each kind of `Order`, etc.)
201
+ * Less is more: the less test data you create, the more meaningful & memorable
202
+ it will be to yourself and your teammates when writing tests. Don't keep
203
+ adding test data unless it will allow you to exercise additional application
204
+ code (e.g. enough `Project` models to require pagination, but not hundreds of
205
+ them for the sake of looking "production-like")
206
+ * Memorable names can become memes for the team to quickly recall and reference
207
+ later (if the admin user is named "Angela" and the manager is "Maria", that'll
208
+ probably serve you better than generic names like "TestUser #1")
209
+
210
+ If you make a mistake when creating your initial set of test data, it's
211
+ perfectly okay to reset the database and start over! Your future tests will be
212
+ coupled to this data as your application grows and evolves, so it's worth taking
213
+ the time to ensure the foundation is solid. (But that's not to say everything
214
+ needs to be perfect; you can always change things or add more data later—you'll
215
+ just have to update your tests accordingly.)
216
+
217
+ ### Step 3: Dump your `test_data` database
218
+
219
+ Once you've created a good sampling of test data by interacting with your app,
220
+ the next step is to flush it from the `test_data` database to SQL files. These
221
+ database dumps are meant to be committed to source control and versioned
222
+ alongside your tests over the life of the application. Additionally, they are
223
+ designed to be incrementally
224
+ [migrated](#step-5-keeping-your-test-data-up-to-date) over time, just like you
225
+ migrate production database with every release.
226
+
227
+ Once you have your test data how you want it, dump the schema and data to SQL
228
+ files with the `test_data:dump` Rake task:
229
+
230
+ ```
231
+ $ bin/rake test_data:dump
232
+ ```
233
+
234
+ This will dump three files into `test/support/test_data`:
235
+
236
+ * `schema.sql` - Schema DDL used to (re-)initialize the `test_data` environment
237
+ database for anyone looking to update your test data
238
+
239
+ * `data.sql` - The test data itself, exported as a bunch of SQL `INSERT`
240
+ statements, which will be executed by your tests to load your test data
241
+
242
+ * `non_test_data.sql` - Data needed to run the `test_data` environment, but
243
+ which shouldn't be inserted by your tests (the `ar_internal_metadata` and
244
+ `schema_migrations` tables, by default; see `config.non_test_data_tables`)
245
+
246
+ You probably won't need to, but these paths can be overridden with
247
+ [TestData.config](#testdataconfig) method. Additional details can also be found
248
+ in the [test_data:dump](#test_datadump) Rake task reference.
249
+
250
+ Once you've made your initial set of dumps, briefly inspect them and—if
251
+ everything looks good—commit them. (And if the files are gigantic or full of
252
+ noise, you might find [these ideas
253
+ helpful](#are-you-sure-i-should-commit-these-sql-dumps-theyre-way-too-big)).
254
+
255
+ Does it feel weird to dump and commit SQL files? That's okay! It's [healthy to
256
+ be skeptical](https://twitter.com/searls/status/860553435116187649?s=20)
257
+ whenever you're asked to commit a generated file! Remember that the `test_data`
258
+ environment exists only for creating your test data. Your tests will, in turn,
259
+ load the SQL dump of your data into the `test` database, and things will proceed
260
+ just as if you'd been loading [Rails' built-in
261
+ fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
262
+ from a set of YAML files.
263
+
264
+ ### Step 4: Load your data in your tests
265
+
266
+ Now that you've dumped the contents of your `test_data` database, you can start
267
+ writing tests that rely on this test data.
268
+
269
+ To accomplish this, you'll likely want to add hooks to run before each test to
270
+ put the database into whatever state the test needs.
271
+
272
+ For the simplest case—ensuring your test data is loaded into the `test` database
273
+ and available to your test, you'll want to call the
274
+ [TestData.uses_test_data](#testdatauses_test_data) method at the beginning of
275
+ the test. The first time `uses_test_data` is called, `test_data` will start a
276
+ transaction and insert your test data. On subsequent calls to `uses_test_data`
277
+ by later tests, the transaction will be rolled back to a save point taken just
278
+ after the data was initially loaded, so that each test gets a clean starting
279
+ point without repeatedly executing the expensive SQL operation.
280
+
281
+ #### If you want every single test to have access to your test data
282
+
283
+ If, for the sake of consistency & simplicity you want every single Rails-aware
284
+ test to have access to your test data, you
285
+ can accomplish this with a single global before-each hook.
286
+
287
+ If you're using Rails' default
288
+ [Minitest](https://github.com/seattlerb/minitest), you can load it in a `setup`
289
+ hook in `ActiveSupport::TestCase`:
10
290
 
11
291
  ```ruby
12
- gem 'test_data'
292
+ class ActiveSupport::TestCase
293
+ setup do
294
+ TestData.uses_test_data
295
+ end
296
+ end
13
297
  ```
14
298
 
15
- And then execute:
299
+ Likewise, if you use [RSpec](https://rspec.info), you can accomplish the same
300
+ thing with global `before(:each)` hook in your `rails_helper.rb` file:
301
+
302
+ ```ruby
303
+ RSpec.configure do |config|
304
+ config.before(:each) do
305
+ TestData.uses_test_data
306
+ end
307
+ end
308
+ ```
309
+
310
+ #### If some tests rely on test data and others need a clean slate
311
+
312
+ Of course, for simple units of code, it may be more prudent to manually create
313
+ the test data they need inline as opposed to relying on a shared source of test
314
+ data. For these tests, you can call
315
+ [TestData.uses_clean_slate](#testdatauses_clean_slate) in a `setup` hook.
316
+
317
+ For the best performance, you might consider a mode-switching method that's
318
+ invoked at the top of each test listing like this:
319
+
320
+ ```ruby
321
+ class ActiveSupport::TestCase
322
+ def self.uses(mode)
323
+ case mode
324
+ when :clean_slate
325
+ setup { TestData.uses_clean_slate }
326
+ when :test_data
327
+ setup { TestData.uses_test_data }
328
+ else
329
+ raise "Invalid test data mode: #{mode}"
330
+ end
331
+ end
332
+ end
333
+
334
+ # A simple model that will `create` its own data
335
+ class WidgetTest < ActiveSupport::TestCase
336
+ uses :clean_slate
337
+ # …
338
+ end
339
+
340
+ # An integrated test that depends on a lot of data
341
+ class KitchenSinkTest < ActionDispatch::IntegrationTest
342
+ uses :test_data
343
+ # …
344
+ end
345
+ ```
346
+
347
+ Or, with RSpec:
348
+
349
+ ```ruby
350
+ module TestDataModes
351
+ def uses(mode)
352
+ case mode
353
+ when :clean_slate
354
+ before(:each) { TestData.uses_clean_slate }
355
+ when :test_data
356
+ before(:each) { TestData.uses_test_data }
357
+ else
358
+ raise "Invalid test data mode: #{mode}"
359
+ end
360
+ end
361
+ end
362
+
363
+ RSpec.configure do |config|
364
+ config.extend(TestDataModes)
365
+ end
366
+
367
+ RSpec.describe Widget, type: :model do
368
+ uses :clean_slate
369
+ # …
370
+ end
371
+
372
+ RSpec.describe "Kitchen sink", type: :request do
373
+ uses :test_data
374
+ # …
375
+ end
376
+ ```
377
+
378
+ #### If your situation is more complicated
379
+
380
+ If you're adding `test_data` to an existing application, it's likely that you
381
+ won't be able to easily adopt a one-size-fits-all approach to test setup across
382
+ your entire suite. Some points of reference, if that's the situation you're in:
383
+
384
+ * If your test suite is already using fixtures or factories and the above hooks
385
+ just broke everything, check out our [interoperability
386
+ guide](#factory--fixture-interoperability-guide) for help.
387
+ * If you don't want `test_data` managing transactions and cleanup for you and
388
+ just want to load the SQL dump, you can call
389
+ [TestData.insert_test_data_dump](#testdatainsert_test_data_dump)
390
+ * For more information on how all this works, see the [API
391
+ reference](#api-reference).
392
+
393
+ ### Step 5: Keeping your test data up-to-date
394
+
395
+ Your app relies on its tests and your tests rely on their test data. This
396
+ creates a bit of a paradox: creating & maintaining test data is _literally_ a
397
+ tertiary concern but simultaneously an inescapable responsibility that will live
398
+ with you for the life of your application. That's true whether you use this gem,
399
+ `factory_bot`, Rails fixtures, or something else as a source of shared test
400
+ data.
401
+
402
+ Fortunately, we already have a fantastic tool available for keeping our
403
+ `test_data` database up-to-date over the life of our application: [Rails
404
+ migrations](https://guides.rubyonrails.org/active_record_migrations.html). If
405
+ your migrations are resilient enough for your production database, they should
406
+ also be able to keep your `test_data` database up-to-date. (As a happy side
407
+ effect of running your migrations against your test data, this means your
408
+ `test_data` database may help you identify hard-to-catch migration bugs early,
409
+ before being deployed to production!)
410
+
411
+ Whenever you create a new migration or add a major feature, you'll probably need
412
+ to update your test data. Here's how to do it:
413
+
414
+ * If the current SQL dumps in `test/support/test_data` are newer than your local
415
+ `test_data` database:
416
+
417
+ 1. Be sure there's nothing in your local `test_data` database that you added
418
+ intentionally and forgot to dump, because it's about to be erased
419
+
420
+ 2. Run `rake test_data:drop_database`
421
+
422
+ 3. Run `rake test_data:load` to recreate the `test_data` database and load
423
+ the latest SQL dumps into it
424
+
425
+ 4. Run any pending migrations with `RAILS_ENV=test_data bin/rake db:migrate`
426
+
427
+ 5. If you need to create any additional data, start up the server
428
+ (`RAILS_ENV=test_data bin/rails s`), just like in [Step
429
+ 2](#step-2-create-some-test-data)
430
+
431
+ 6. Export your newly-updated `test_data` database with `rake test_data:dump`
432
+
433
+ 7. Ensure your tests are passing and then commit the resulting SQL files
434
+
435
+ * If the local `test_data` database is already up-to-date with the current SQL
436
+ dumps, follow steps **4 through 7** above
437
+
438
+ It's important to keep in mind that your test data SQL dumps are a shared,
439
+ generated resource among your team (just like a `structure.sql` or `schema.rb`
440
+ file). As a result, if your team doesn't integrate code frequently or if the
441
+ test data changes frequently, you'd be right to be concerned that [the resulting
442
+ merge conflicts could become
443
+ significant](#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),
444
+ so sweeping changes should be made deliberately and in collaboration with other
445
+ contributors.
446
+
447
+ _[Aside: some Rails teams are averse to using migrations to migrate data as well
448
+ as schemas, instead preferring one-off scripts and tasks. You'll have an easier
449
+ time of things if you use migrations for both schema and data changes. Here are
450
+ some notes on [how to write data migrations
451
+ safely](https://blog.testdouble.com/posts/2014-11-04-healthy-migration-habits/#habit-4-dont-reference-models).
452
+ Otherwise, you'll need to remember to run any ad hoc deployment scripts against
453
+ your `test_data` Rails environment along with each of your other deployed
454
+ environments.]_
455
+
456
+ ## Factory & Fixture Interoperability Guide
457
+
458
+ Let's be real, most Rails apps already have some tests, and most of those test
459
+ suites will already be relying on
460
+ [factory_bot](https://github.com/thoughtbot/factory_bot) or Rails' built-in
461
+ [test
462
+ fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures).
463
+ While `test_data` is designed to be an alternative to both of these approaches
464
+ to managing your test data, it wouldn't be practical to ask a team to rewrite
465
+ all their existing tests in order to migrate to a different tool. That's why the
466
+ `test_data` gem goes to great lengths to play nicely with your existing tests,
467
+ while ensuring each test is wrapped in an isolated and fast always-rolled-back
468
+ transaction—regardless if the test depends on `test_data`, factories, fixtures,
469
+ all three, or none-of-the-above.
470
+
471
+ This section will hopefully make it a little easier to incorporate new
472
+ `test_data` tests into a codebase that's already using `factory_bot` and/or
473
+ Rails fixtures, whether you choose to incrementally migrate to using `test_data`
474
+ over time.
475
+
476
+ ### Using `test_data` with `factory_bot`
477
+
478
+ This section will document some thoughts and strategies for introducing
479
+ `test_data` to a test suite that's already using `factory_bot`.
480
+
481
+ #### Getting your factory tests passing after adding `test_data`
482
+
483
+ Depending on the assumptions your tests make about the state of the database
484
+ before you've loaded any factories, it's possible that everything will "just
485
+ work" after adding [TestData.uses_test_data](#testdatauses_test_data) in a
486
+ before-each hook (as shown in the [setup
487
+ guide](#step-4-load-your-data-in-your-tests)). So by all means, try running your
488
+ suite after following the initial setup guide and see if the suite just passes.
489
+
490
+ If you find that your test suite is failing after adding
491
+ `TestData.uses_test_data` to your setup, don't panic! Test failures are most
492
+ likely caused by the combination of your `test_data` database with the data
493
+ persisted by your factories.
494
+
495
+ One approach would be to attempt to resolve each such failure one-by-one—usually
496
+ by updating the offending factories or editing your `test_data` database to
497
+ ensure they steer clear of one another. Care should be taken to preserve the
498
+ conceptual encapsulation of each test, however, as naively squashing errors can
499
+ introduce inadvertent coupling between your factories and your `test_data`
500
+ database such that neither can be used independently of the other.
501
+
502
+ Another approach that the `test_data` gem provides is an additional mode with
503
+ `TestData.uses_clean_slate`, which—when called at the top of a factory-dependent
504
+ test—will ensure that the tables that `test_data` had written to will be
505
+ truncated, allowing the test to create whatever factories it needs without fear
506
+ of conflicts.
507
+
508
+ ```ruby
509
+ class AnExistingFactoryUsingTest < ActiveSupport::Testcase
510
+ setup do
511
+ TestData.uses_clean_slate
512
+ # pre-existing setup
513
+ end
514
+ # …
515
+ end
516
+ ```
517
+
518
+ If you have a lot of tests, you can find a more sophisticated approaches for
519
+ logically switching between types of test data declaratively above in the
520
+ [getting started
521
+ section](#if-some-tests-rely-on-test-data-and-others-need-a-clean-slate)
522
+
523
+ ### Using `test_data` with Rails fixtures
524
+
525
+ While [Rails
526
+ fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
527
+ are similar to factories, the fact that they're run globally by Rails and
528
+ permanently committed to the test database actually makes them a little trickier
529
+ to work with. This section will cover a couple approaches for integrating
530
+ `test_data` into suites that use fixtures.
531
+
532
+ It's more likely than not that all your tests will explode in dramatic fashion
533
+ as soon as you add `TestData.uses_test_data` to a `setup` or `before(:each)`
534
+ hook. Typically, your fixtures will be loaded and committed immediately with
535
+ your `test_data` dump inserted afterward, which makes it exceedingly likely that
536
+ your tests will fail with primary key and unique constraint conflicts. If that's
537
+ the case you find yourself in, `test_data` provides an API that **overrides
538
+ Rails' built-in fixtures behavior with a monkey patch**.
539
+
540
+ And if that bold text wasn't enough to scare you off, here's how to do
541
+ it:
542
+
543
+ 1. Before your tests have loaded (e.g. near the top of your test helper), call:
544
+ [TestData.prevent_rails_fixtures_from_loading_automatically!](#testdataprevent_rails_fixtures_from_loading_automatically)
545
+ This will patch Rails'
546
+ [setup_fixtures](https://github.com/rails/rails/blob/main/activerecord/lib/active_record/test_fixtures.rb#L105)
547
+ and effectively render it into a no-op, which means that your test fixtures
548
+ will not be automatically loaded into your test database
549
+
550
+ 2. In tests that rely on your `test_data` dump, call
551
+ [TestData.uses_test_data](#step-4-load-your-data-in-your-tests) as you
552
+ normally would. Because your fixtures won't be loaded automatically, they
553
+ won't be available to these tests
554
+
555
+ 3. In tests that need fixtures, call
556
+ [TestData.uses_rails_fixtures(self)](#testdatauses_rails_fixtures) in a
557
+ before-each hook. This will first ensure that any tables written to by
558
+ `test_data` are truncated (as with `TestData.uses_clean_slate`) before
559
+ loading your Rails fixtures
560
+
561
+ For example, you might add the following to an existing fixtures-dependent
562
+ test to get it passing:
563
+
564
+ ```ruby
565
+ class AnExistingFixtureUsingTest < ActiveSupport::Testcase
566
+ setup do
567
+ TestData.uses_rails_fixtures(self)
568
+ # pre-existing setup
569
+ end
570
+
571
+ # …
572
+ end
573
+ ```
574
+
575
+ If you've adopted a mode-switching helper method [like the one described
576
+ above](#if-some-tests-rely-on-test-data-and-others-need-a-clean-slate), you
577
+ could of course add a third mode to cover any tests that depend on Rails
578
+ fixtures.
579
+
580
+ ## Rake Task Reference
581
+
582
+ ### test_data:install
583
+
584
+ A meta-task that runs [test_data:configure](#test_dataconfigure) and [test_data:initialize](#test_datainitialize).
585
+
586
+ ### test_data:configure
587
+
588
+ This task runs several generators:
589
+
590
+ * `config/environments/test_data.rb` - As you may know, Rails ships with
591
+ `development`, `test`, and `production` environments defined by default. But
592
+ you can [actually define custom
593
+ environments](https://guides.rubyonrails.org/configuring.html#creating-rails-environments),
594
+ too! This gem adds a new `test_data` environment and database that's intended
595
+ to be used to create and dump your test data. This new environment file loads
596
+ your `development` environment's configuration and disables migration schema
597
+ dumps so that you can run migrations against your `test_data` database without
598
+ affecting your app's `schema.rb` or `structure.sql`.
599
+
600
+ * `config/initializers/test_data.rb` - Creates an initializer for the gem that
601
+ calls [TestData.config](#testdataconfig) with an empty block and comments
602
+ documenting the currently-available options and their default values
603
+
604
+ * `config/database.yml` - This generator adds a new `test_data` section to your
605
+ database configuration, named with the same scheme as your other databases
606
+ (e.g. `your_app_test_data`). If your configuration resembles Rails' generated
607
+ `database.yml` and has a working `&default` alias, then this should "just
608
+ work"
609
+
610
+ * `config/webpacker.yml` - The gem has nothing to do with web assets, but
611
+ [webpacker](https://github.com/rails/webpacker) will display some prominent
612
+ warnings or errors if it is loaded without a configuration entry for the
613
+ currently-running environment, so this generator defines an alias based on
614
+ your `development` config and then defines `test_data` as extending it
615
+
616
+ * `config/secrets.yml` - If your app still uses (the now-deprecated)
617
+ [secrets.yml](https://guides.rubyonrails.org/4_1_release_notes.html#config-secrets-yml)
618
+ file introduced in Rails 4.1, this generator will ensure that the `test_data`
619
+ environment is accounted for with a generated `secret_key_base` value. If you
620
+ have numerous secrets in this file's `development:` stanza, you may want to
621
+ alias and inherit it into `test_data:` like the `webpacker.yml` generator does
622
+
623
+ * `config/cable.yml` - Simply defines a `test_data:` entry that tells
624
+ [ActionCable](https://guides.rubyonrails.org/action_cable_overview.html) to
625
+ use the `async` adapter, since that's also the default for `development`
626
+
627
+ ### test_data:verify_config
628
+
629
+ This task will verify that your configuration appears to be valid by checking
630
+ with each of the gem's generators to inspect your configuration files, and will
631
+ error whenever a configuration problem is detected.
632
+
633
+ ### test_data:initialize
634
+
635
+ This task gets your local `test_data` database up-and-running, either from a set
636
+ of dump files (if they already exist), or by loading your schema and running
637
+ your seed file. Specifically:
638
+
639
+ 1. Creates the `test_data` environment's database, if it doesn't already exist
640
+
641
+ 2. Ensures the database is non-empty to preserve data integrity (run
642
+ [test_data:drop_database](#test_datadrop_database) first if you intend to
643
+ reinitialize it)
644
+
645
+ 3. Checks to see if a dump of the database already exists (by default, stored in
646
+ `test/support/test_data/`)
647
+
648
+ * If dumps do exist, it invokes [test_data:load](#test_dataload) to load
649
+ them into the database
650
+
651
+ * Otherwise, it invokes the task `db:schema:load` and `db:seed` (similar to
652
+ Rails' built-in `db:setup` task)
653
+
654
+ ### test_data:dump
655
+
656
+ This task is designed to be run after you've created or updated your test data
657
+ in the `test_data` database and you're ready to run your tests against it. The
658
+ task creates several plain SQL dumps from your `test_data` environment's
659
+ database:
660
+
661
+ * A schema-only dump, by default in `test/support/test_data/schema.sql`
16
662
 
17
- $ bundle install
663
+ * A data-only dump of records you want to be loaded in your tests, by default in
664
+ `test/support/test_data/data.sql`
665
+
666
+ * A data-only dump of records that you *don't* want loaded in your tests in
667
+ `test/support/test_data/non_test_data.sql`. By default, this includes Rails'
668
+ internal tables: `ar_internal_metadata` and `schema_migrations`, configurable
669
+ with [TestData.config](#testdataconfig)'s `non_test_data_tables`
670
+
671
+ Each of these files are designed to be committed and versioned with the rest of
672
+ your application. [TestData.config](#testdataconfig) includes several
673
+ options to control this task.
674
+
675
+ ### test_data:load
676
+
677
+ This task will load your SQL dumps into your `test_data` database by:
678
+
679
+ 1. Verifying the `test_data` environment's database is empty (creating it if it
680
+ doesn't exist and failing if it's not empty)
681
+
682
+ 2. Verifying that your schema, test data, and non-test data SQL dumps can be
683
+ found at the configured paths
684
+
685
+ 3. Loading the dumps into the `test_data` database
686
+
687
+ 4. Warning if there are pending migrations that haven't been run yet
688
+
689
+ If there are pending migrations, you'll probably want to run them and then
690
+ dump & commit your test data so that they're up-to-date:
691
+
692
+ ```
693
+ $ RAILS_ENV=test_data bin/rake db:migrate
694
+ $ bin/rake test_data:dump
695
+ ```
696
+
697
+ ### test_data:create_database
698
+
699
+ This task will create the `test_data` environment's database if it does not
700
+ already exist. It also
701
+ [enhances](https://dev.to/molly/rake-task-enhance-method-explained-3bo0) Rails'
702
+ `db:create` task so that `test_data` is created along with `development` and
703
+ `test` whenever `rake db:create` is run.
704
+
705
+ ### test_data:drop_database
706
+
707
+ This task will drop the `test_data` environment's database if it exists. It also
708
+ enhances Rails' `db:drop` task so that `test_data` is dropped along with
709
+ `development` and `test` whenever `rake db:drop` is run.
710
+
711
+ ## API Reference
712
+
713
+ ### TestData.uses_test_data
714
+
715
+ This is the method designed to be used by your tests to load your test data
716
+ into your `test` database so that your tests can rely on it. Typically, you'll
717
+ want to call it at the beginning of each test that relies on the test data
718
+ managed by this gem—most often, in a before-each hook.
719
+
720
+ For the sake of speed and integrity, `TestData.uses_test_data` is designed to
721
+ take advantage of nested transactions ([Postgres
722
+ savepoints](https://www.postgresql.org/docs/current/sql-savepoint.html)). By
723
+ default, data is loaded in a transaction and intended to be rolled back to the
724
+ point _immediately after_ the data was imported between tests. This way, your
725
+ test suite only pays the cost of importing the SQL file once, but each of your
726
+ tests can enjoy a clean slate that's free of data pollution from other tests.
727
+ (This is similar to, but separate from, Rails fixtures'
728
+ [use_transactional_tests](https://edgeguides.rubyonrails.org/testing.html#testing-parallel-transactions)
729
+ option.)
730
+
731
+ _See configuration option:
732
+ [config.after_test_data_load](#configafter_test_data_load)_
733
+
734
+ ### TestData.uses_clean_slate
735
+
736
+ If a test does not rely on your `test_data` data, you can instead ensure that it
737
+ runs against empty tables by calling `TestData.uses_clean_slate`. Like
738
+ `TestData.uses_test_data`, this would normally be called at the beginning of
739
+ each such test in a before-each hook.
740
+
741
+ This method works by first ensuring that your test data is loaded (and the
742
+ correspondent savepoint created), then will truncate all affected tables and
743
+ create another savepoint. It's a little counter-intuitive that you'd first
744
+ litter your database with data only to wipe it clean again, but it's much faster
745
+ to repeatedly truncate tables than to repeatedly import large SQL files.
746
+
747
+ _See configuration options:
748
+ [config.after_test_data_truncate](#configafter_test_data_truncate),
749
+ [config.truncate_these_test_data_tables](#configtruncate_these_test_data_tables)_
750
+
751
+ ### TestData.uses_rails_fixtures
752
+
753
+ As described in this README's [fixture interop
754
+ guide](#using-test_data-with-rails-fixtures), `TestData.uses_rails_fixtures`
755
+ will load your app's [Rails
756
+ fixtures](https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures)
757
+ by intercepting Rails' built-in fixture-loading code. As with the other "uses"
758
+ methods, you'll likely want to call it in a before-each hook before any test
759
+ that needs access to your Rails fixtures.
760
+
761
+ There are two additional things to keep in mind if using this method:
762
+
763
+ 1. Using this feature requires that you've first invoked
764
+ [TestData.prevent_rails_fixtures_from_loading_automatically!](#testdataprevent_rails_fixtures_from_loading_automatically)
765
+ to override Rails' default behavior before any of your tests have loaded or
766
+ started running
767
+
768
+ 2. Because the method depends on Rails' fixture caching mechanism, it must be
769
+ passed an instance of the running test class (e.g.
770
+ `TestData.uses_rails_fixtures(self)`)
771
+
772
+ Under the hood, this method effectively ensures a clean slate the same way
773
+ `TestData.uses_clean_slate` does, except that after creating the truncation
774
+ savepoint, it will then load your fixtures and finally create—wait for it—yet
775
+ another savepoint that subsequent calls to `uses_rails_fixtures` can rollback
776
+ to.
777
+
778
+ _See configuration option:
779
+ [config.after_rails_fixture_load](#configafter_rails_fixture_load)_
780
+
781
+ #### TestData.prevent_rails_fixtures_from_loading_automatically!
782
+
783
+ Call this method before any tests have been loaded or executed by your test
784
+ runner if you're planning to use
785
+ [TestData.uses_rails_fixtures](#testdatauses_rails_fixtures) to load Rails
786
+ fixtures into any of your tests. This method will disable the default behavior
787
+ of loading your Rails fixtures into the test database as soon as the first test
788
+ case with fixtures enabled is executed. (Inspect the [source for the
789
+ patch](/lib/test_data/active_record_ext.rb) to make sure you're comfortable with
790
+ what it's doing.)
791
+
792
+ ### TestData.config
793
+
794
+ The generated `config/initializers/test_data.rb` initializer will include a call
795
+ to `TestData.config`, which takes a block that yields a mutable configuration
796
+ object (similar to `Rails.application.config`). If anything is unclear after
797
+ reading the documentation, feel free to review the
798
+ [initializer](lib/generators/test_data/initializer_generator.rb) and the [Config
799
+ class](/lib/test_data/config.rb) themselves.
800
+
801
+ #### Lifecycle hooks
802
+
803
+ Want to shift forward several timestamp fields after your `test_data` SQL dumps
804
+ are loaded into your test database? Need to refresh a materialized view after
805
+ your Rails fixtures are loaded? You _could_ do these things after calling
806
+ `TestData.uses_test_data` and `TestData.uses_rails_fixtures`, respectively, but
807
+ you'd take the corresponding performance hit in each and every test.
808
+
809
+ Instead, you can pass a callable or a block and `test_data` will execute it just
810
+ _after_ performing the associated data operation but just _before_ creating a
811
+ transaction savepoint. That way, whenever the gem rolls back between tests, your
812
+ hook won't need to be run again.
813
+
814
+ ##### config.after_test_data_load
815
+
816
+ This is hook is run immediately after `TestData.uses_test_data` has loaded your
817
+ SQL dumps into the `test` database, but before creating a savepoint. Takes a
818
+ block or anything that responds to `call`.
819
+
820
+
821
+ ```ruby
822
+ TestData.config do |config|
823
+ # Example: roll time forward
824
+ config.after_test_data_load do
825
+ Boop.connection.exec_update(<<~SQL, nil, [[nil, Time.zone.now - System.epoch]])
826
+ update boops set booped_at = booped_at + $1
827
+ SQL
828
+ end
829
+ end
830
+ ```
831
+
832
+ ##### config.after_test_data_truncate
833
+
834
+ This is hook is run immediately after `TestData.uses_clean_slate` has truncated
835
+ your test data, but before creating a savepoint. Takes a block or anything that
836
+ responds to `call`.
837
+
838
+ ```ruby
839
+ TestData.config do |config|
840
+ # Example: pass a callable instead of a block
841
+ config.after_test_data_truncate(SomethingThatRespondsToCall.new)
842
+ end
843
+ ```
844
+
845
+ ##### config.after_rails_fixture_load
846
+
847
+ This is hook is run immediately after `TestData.uses_rails_fixtures` has loaded
848
+ your Rails fixtures into the `test` database, but before creating a savepoint.
849
+ Takes a block or anything that responds to `call`.
850
+
851
+ ```ruby
852
+ TestData.config do |config|
853
+ # Example: refresh Postgres assets like materialized views
854
+ config.after_rails_fixture_load do
855
+ RefreshesMaterializedViews.new.call
856
+ end
857
+ end
858
+ ```
859
+
860
+ #### test_data:dump options
861
+
862
+ The gem provides several options governing the behavior of the
863
+ [test_data:dump](#test_datadump) Rake task. You probably won't need to set these
864
+ unless you run into a problem with the defaults.
865
+
866
+ ##### config.non_test_data_tables
867
+
868
+ Your application may have some tables that are necessary for the operation of
869
+ the application, but irrelevant or incompatible with you your tests. This data
870
+ is still dumped for the sake of being able to restore the database with [rake
871
+ test_data:load](#test_dataload), but will not be loaded when your tests are
872
+ running. Defaults to `[]`, (but will always include `ar_internal_metadata` and
873
+ `schema_migrations`).
874
+
875
+ ```ruby
876
+ TestData.config do |config|
877
+ config.non_test_data_tables = []
878
+ end
879
+ ```
880
+
881
+ ##### config.dont_dump_these_tables
882
+
883
+ Some tables populated by your application may not be necessary to either its
884
+ proper functioning or useful to your tests (e.g. audit logs), so you can save
885
+ time and storage by preventing those tables from being dumped entirely. Defaults
886
+ to `[]`.
887
+
888
+ ```ruby
889
+ TestData.config do |config|
890
+ config.dont_dump_these_tables = []
891
+ end
892
+ ```
893
+
894
+ ##### config.schema_dump_path
895
+
896
+ The path to which the schema DDL of your `test_data` database will be written.
897
+ This is only used by [rake test_data:load](#test_dataload) when initializing the
898
+ `test_data` database. Defaults to `"test/support/test_data/schema.sql"`.
899
+
900
+ ```ruby
901
+ TestData.config do |config|
902
+ config.schema_dump_path = "test/support/test_data/schema.sql"
903
+ end
904
+ ```
905
+
906
+ ##### config.data_dump_path
907
+
908
+ The path that the SQL dump of your test data will be written. This is the dump
909
+ that will be executed by `TestData.uses_test_data` in your tests. Defaults to
910
+ `"test/support/test_data/data.sql"`.
911
+
912
+ ```ruby
913
+ TestData.config do |config|
914
+ config.data_dump_path = "test/support/test_data/data.sql"
915
+ end
916
+ ```
917
+
918
+ ##### config.non_test_data_dump_path
919
+
920
+ The path to which the [non_test_data_tables](#confignon_test_data_tables) in
921
+ your `test_data` database will be written. This is only used by [rake
922
+ test_data:load](#test_dataload) when initializing the `test_data` database.
923
+ Defaults to `"test/support/test_data/non_test_data.sql"`.
924
+
925
+ ```ruby
926
+ TestData.config do |config|
927
+ config.non_test_data_dump_path = "test/support/test_data/non_test_data.sql"
928
+ end
929
+ ```
930
+
931
+ #### Other configuration options
932
+
933
+ ##### config.truncate_these_test_data_tables
934
+
935
+ By default, when [TestData.uses_clean_slate](#testdatauses_clean_slate) is
936
+ called, it will truncate any tables for which an `INSERT` operation was
937
+ detected in your test data SQL dump. This may not be suitable for every case,
938
+ however, so this option allows you to specify which tables are truncated.
939
+ Defaults to `nil`.
940
+
941
+ ```ruby
942
+ TestData.config do |config|
943
+ config.truncate_these_test_data_tables = []
944
+ end
945
+ ```
946
+
947
+ ##### config.log_level
948
+
949
+ The gem outputs its messages to standard output and error by assigning a log
950
+ level to each message. Valid values are `:debug`, `:info`, `:warn`, `:error`,
951
+ `:quiet`. Defaults to `:info`.
952
+
953
+ ```ruby
954
+ TestData.config do |config|
955
+ config.log_level = :info
956
+ end
957
+ ```
958
+
959
+ ### TestData.insert_test_data_dump
960
+
961
+ If you just want to insert the test data in your application's SQL dumps without
962
+ any of the transaction management or test runner assumptions inherent in
963
+ [TestData.uses_test_data](#testdatauses_test_data), then you can call
964
+ `TestData.insert_test_data_dump` to load and execute the dump.
965
+
966
+ This might be necessary in a few different situations:
967
+
968
+ * Running tests in environments that can't be isolated to a single database
969
+ transaction (e.g. orchestrating tests across multiple databases, processes,
970
+ etc.)
971
+ * You might ant to use your test data to seed pre-production environments with
972
+ enough data to exploratory test (as you might do in a `postdeploy` script with
973
+ your [Heroku Review
974
+ Apps](https://devcenter.heroku.com/articles/github-integration-review-apps))
975
+ * Your tests require complex heterogeneous sources of data that aren't a good
976
+ fit for the assumptions and constraints of this library's default methods for
977
+ preparing test data
978
+
979
+ In any case, since `TestData.insert_test_data_dump` is not wrapped in a
980
+ transaction, when used for automated tests, data cleanup becomes your
981
+ responsibility.
982
+
983
+ ## Assumptions
984
+
985
+ The `test_data` gem is still brand new and doesn't cover every use case just
986
+ yet. Here are some existing assumptions and limitations:
987
+
988
+ * You're using Postgres
989
+
990
+ * You're using Rails 6 or higher
991
+
992
+ * Your app does not require Rails' [multi-database
993
+ support](https://guides.rubyonrails.org/active_record_multiple_databases.html)
994
+ in order to be tested
995
+
996
+ * Your app has the binstubs `bin/rake` and `bin/rails` that Rails generates and
997
+ they work (protip: you can regenerate them with `rails app:update:bin`)
998
+
999
+ * Your `database.yml` defines a `&default` alias from which to extend the
1000
+ `test_data` database configuration (if your YAML file lacks one, you can
1001
+ always specify the `test_data` database configuration manually)
1002
+
1003
+ ## Fears, Uncertainties, and Doubts
1004
+
1005
+ ### But we use and like `factory_bot` and so I am inclined to dislike everything about this gem!
1006
+
1007
+ If you use `factory_bot` and all of these are true:
1008
+
1009
+ * Your integration tests are super fast and are not getting significantly slower
1010
+ over time
1011
+
1012
+ * Minor changes to existing factories rarely result in test failures that
1013
+ require unrelated tests to be read & updated to get them passing again
1014
+
1015
+ * The number of associated records generated between your most-used factories
1016
+ are representative of production data, as opposed to generating a sprawling
1017
+ hierarchy of models, as if your test just ordered "one of everything" off the
1018
+ menu
1019
+
1020
+ * Your default factories generate models that resemble real records created by
1021
+ your production application, as opposed to representing the
1022
+ sum-of-all-edge-cases with every boolean flag enabled and optional attribute
1023
+ set
1024
+
1025
+ * You've avoided mitigating the above problems with confusingly-named and
1026
+ confidence-eroding nested factories with names like `:user`, `:basic_user`,
1027
+ `:lite_user`, and `:plain_user_no_associations_allowed`
1028
+
1029
+ If none of these things are true, then congratulations! You are probably using
1030
+ `factory_bot` to great effect! Unfortunately, in our experience, this outcome
1031
+ is exceedingly rare, especially for large and long-lived applications.
1032
+
1033
+ However, if you'd answer "no" to any of the above questions, just know that
1034
+ these are the sorts of failure modes the `test_data` gem was designed to
1035
+ avoid—and we hope you'll consider trying it with an open mind. At the same time,
1036
+ we acknowledge that large test suites can't be rewritten and migrated to a
1037
+ different source of test data overnight—nor should they be! See our notes on
1038
+ [migrating to `test_data`
1039
+ incrementally](#factory--fixture-interoperability-guide)
1040
+
1041
+ ### 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?
1042
+
1043
+ In a word: carefully!
1044
+
1045
+ First, in terms of expectations-setting, you should expect your test data SQL
1046
+ dumps to churn at roughly the same rate as your schema: lots of changes up
1047
+ front, but tapering off as the application stabilizes.
1048
+
1049
+ If your schema isn't changing frequently and you're not running data migrations
1050
+ against production very often, it might make the most sense to let this concern
1051
+ present itself as a real problem before attempting to solve it, as you're likely
1052
+ to find that other best-practices around collaboration and deployment (frequent
1053
+ merges, continuous integration, coordinating breaking changes) will also manage
1054
+ this risk. The reason that the dumps are stored as plain SQL (aside from the
1055
+ fact that git's text compression is very good) is to make merge conflicts with
1056
+ other branches feasible, if not entirely painless.
1057
+
1058
+ However, if your app is in the very initial stages of development or you're
1059
+ otherwise making breaking changes to your schema and data very frequently, our
1060
+ best advice is to hold off a bit on writing _any_ integration tests that depend
1061
+ on shared sources of test data (regardless of tool), as they'll be more likely
1062
+ to frustrate your ability to rapidly iterate than detect bugs. Once you you have
1063
+ a reasonably stable feature working end-to-end, that's a good moment to start
1064
+ adding integration tests—and perhaps pulling in a gem like this one to help you.
1065
+
1066
+ ### Why can't I save multiple database dumps to cover different scenarios?
1067
+
1068
+ For the same reason you (probably) don't have multiple production databases: the
1069
+ fact that Rails apps are monolithic and consolidated is a big reason why they're
1070
+ so productive and comprehensible. This gem is not
1071
+ [VCR](https://github.com/vcr/vcr) for databases. If you were to design separate
1072
+ test data dumps for each feature, stakeholder, or concern, you'd also have more
1073
+ moving parts to maintain, more complexity to communicate, and more pieces that
1074
+ could someday fall into disrepair.
1075
+
1076
+ By having a single `test_data` database that grows up with your application just
1077
+ like `production` does—with both having their schemas and data migrated
1078
+ incrementally over time—your integration tests that depend on `test_data` will
1079
+ have an early opportunity to catch bugs that otherwise wouldn't be found until
1080
+ they were deployed into a long-lived staging or (gasp!) production environment.
1081
+
1082
+ ### Are you sure I should commit these SQL dumps? They're way too big!
1083
+
1084
+ If the dump files generated by `test_data:dump` seem massive, consider the
1085
+ cause:
1086
+
1087
+ 1. If you inadvertently created more data than necessary, you might consider
1088
+ resetting (or rolling back) your changes and making another attempt at
1089
+ generating a more minimal set of test data
1090
+
1091
+ 2. If some records persisted by your application aren't very relevant to your
1092
+ tests, you might consider either of these options:
1093
+
1094
+ * If certain tables are necessary for running the app but aren't needed by
1095
+ your tests, you can add them to the `config.non_test_data_tables`
1096
+ configuration array. They'll still be committed to git, but won't loaded
1097
+ by your tests
1098
+
1099
+ * If the certain tables are not needed by your application or by your tests
1100
+ (e.g. audit logs), add them to the `config.dont_dump_these_tables` array,
1101
+ and they won't be persisted by `rake test_data:dump`
1102
+
1103
+ 3. If the dumps are _necessarily_ really big (some apps are complex!), consider
1104
+ looking into [git-lfs](https://git-lfs.github.com) for tracking them without
1105
+ impacting the size and performance of the git slug. (See [GitHub's
1106
+ documentation](https://docs.github.com/en/github/managing-large-files/working-with-large-files)
1107
+ on what their service supports)
1108
+
1109
+ _[Beyond these options, we'd also be interested in a solution that filtered data
1110
+ in a more granular way than ignoring entire tables. If you have a proposal you'd
1111
+ be interested in implementing, [suggest it in an issue](/issues/new)!]_
1112
+
1113
+ ### Tests shouldn't use shared test data, they should instantiate the objects they need!
1114
+
1115
+ Agreed! Nothing is simpler than calling `new` to create an object.
1116
+
1117
+ If it's possible to write a test that looks like this, do it. Don't use shared
1118
+ test data loaded from this gem or any other:
1119
+
1120
+ ```ruby
1121
+ def test_exclude_cancelled_orders
1122
+ good_order = Order.new
1123
+ bad_order = Order.new(cancelled: true)
1124
+ user = User.create!(orders: [good_order, bad_order])
1125
+
1126
+ result = user.active_orders
1127
+
1128
+ assert_includes good_order
1129
+ refute_includes bad_order
1130
+ end
1131
+ ```
1132
+
1133
+ This test is simple, self-contained, clearly demarcates the
1134
+ [arrange-act-assert](https://github.com/testdouble/contributing-tests/wiki/Arrange-Act-Assert)
1135
+ phases, and (most importantly) will only fail if the functionality stops
1136
+ working. Maximizing the number of tests that can be written expressively and
1137
+ succinctly without the aid of shared test data is a laudable goal that more
1138
+ teams should embrace.
1139
+
1140
+ However, what if the code you're writing doesn't need 3 records in the database,
1141
+ but 30? Writing that much test setup would be painstaking, despite being
1142
+ fully-encapsulated. Long test setup is harder for others to read and understand.
1143
+ And because that setup depends on more of your system's code, it will have more
1144
+ reasons to break as your codebase changes. At that point, you have two options:
1145
+
1146
+ 1. Critically validate your design: why is it so hard to set up? Does it
1147
+ _really_ require so much persisted data to exercise this behavior? Would a
1148
+ [plain old Ruby
1149
+ object](https://steveklabnik.com/writing/the-secret-to-rails-oo-design) that
1150
+ defined a pure function have been feasible? Could a model instance or even a
1151
+ `Struct` be passed to the
1152
+ [subject](https://github.com/testdouble/contributing-tests/wiki/Subject)
1153
+ instead of loading everything from the database? When automated testing is
1154
+ saved for the very end of a feature's development, it can feel too costly to
1155
+ reexamine design decisions like this, but it can be valuable to consider all
1156
+ the same. *Easy to test code is easy to use code*
1157
+
1158
+ 2. If the complex setup is a necessary reality of the situation that your app
1159
+ needs to handle (and it often will be!), then having _some_ kind of shared
1160
+ source of test data to use as a starting point can be hugely beneficial.
1161
+ That's why `factory_bot` is so popular, why this gem exists, etc.
1162
+
1163
+ As a result, there is no one-size-fits-all approach. Straightforward behavior
1164
+ that can be invoked with a clear, concise test has no reason to be coupled to a
1165
+ shared source of test data. Meanwhile, tests of more complex behaviors that
1166
+ require lots of carefully-arranged data might be unmaintainable without a shared
1167
+ source of test data to lean on. So both kinds of test clearly have their place.
1168
+
1169
+ But this is a pretty nuanced discussion that can be hard to keep in mind when
1170
+ under deadline pressure or on a large team where building consensus around norms
1171
+ is challenging. As a result, leaving the decision of which type of test to write
1172
+ to spur-of-the-moment judgment is likely to result in inconsistent test design.
1173
+ Instead, you might consider separating these two categories into separate test
1174
+ types or suites, with simple heuristics to determine which types of code demand
1175
+ which type of test.
1176
+
1177
+ For example, it would be completely reasonable to load this gem's test data for
1178
+ integration tests, but not for basic tests of models, like so:
1179
+
1180
+ ```ruby
1181
+ class ActionDispatch::IntegrationTest
1182
+ setup do
1183
+ TestData.uses_test_data
1184
+ end
1185
+ end
1186
+
1187
+ class ActiveSupport::TestCase
1188
+ setup do
1189
+ TestData.uses_clean_slate
1190
+ end
1191
+ end
1192
+ ```
18
1193
 
19
- Or install it yourself as:
1194
+ In short, this skepticism is generally healthy, and encapsulated tests that
1195
+ forego reliance on shared sources of test data should be maximized. For
1196
+ everything else, there's `test_data`.
20
1197
 
21
- $ gem install test_data
1198
+ ### I'm worried my tests aren't as fast as they should be
22
1199
 
23
- ## Usage
1200
+ The `test_data` gem was written to enable tests that are not only more
1201
+ comprehensible and maintainable over the long-term, but also _much faster_ to
1202
+ run. That said—and especially if you're adding `test_data` to an existing test
1203
+ suite—care should be taken to audit everything the suite does between tests in
1204
+ order to optimize its overall runtime.
24
1205
 
25
- TODO: Write usage instructions here
1206
+ The first and most likely source of unnecessary slowness is redundant test
1207
+ cleanup—the speed gained from sandwiching every expensive operation between
1208
+ transaction savepoints can be profound… but can also easily be erased by a
1209
+ single before-each hook calling
1210
+ [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner) to
1211
+ commit a truncation of the database. As a result, it's worth taking a little
1212
+ time to take stock of everything that's called between tests during setup &
1213
+ teardown to ensure multiple tools aren't attempting to clean up the state of the
1214
+ database and potentially interfering with one another.
26
1215
 
27
- ## Development
1216
+ A second opportunity for optimization is to group tests that use the same type
1217
+ of test data together, either into separate suites or by preventing them from
1218
+ being run in random order across said types. For example, suppose you have 10
1219
+ tests that call `TestData.uses_test_data` and 10 that call
1220
+ `TestData.uses_rails_fixtures`. If a test that calls `TestData.uses_test_data`
1221
+ is followed by another that calls `uses_test_data`, the only operation needed by
1222
+ the second call will be a rollback to the savepoint taken after the test data
1223
+ was loaded. If, however, a `uses_test_data` test is followed by a
1224
+ `uses_rails_fixtures` test, then the test data will be truncated and the
1225
+ fixtures loaded and new savepoints created (which would then be undone again if
1226
+ the _next_ test happened to call `uses_test_data`).
28
1227
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
1228
+ As a result of the above, the marginal runtime cost for each `TestData.uses_*`
1229
+ method depends on which kinds of test precedes and follows it. That means your
1230
+ tests will run faster overall if the tests that call `TestData.uses_test_data`
1231
+ are run as a group separately from your tests that rely on
1232
+ `TestData.uses_clean_slate` or `TestData.uses_rails_fixtures`. Separating your
1233
+ tests into logical groups pretty trivial if you're using RSpec, as the
1234
+ [tag](https://relishapp.com/rspec/rspec-core/v/3-10/docs/command-line/tag-option)
1235
+ feature was built with this sort of need in mind. If you're using Minitest, you
1236
+ might consider organizing the tests in different directories and running
1237
+ multiple commands to execute them (e.g. `bin/rails test test/test_data_tests`
1238
+ and `bin/rails test/factory_tests`). Every CI configuration is different,
1239
+ however, and you may find yourself needing to get creative in configuring things
1240
+ to achieve the fastest build time.
30
1241
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
1242
+ ## Code of Conduct
32
1243
 
33
- ## Contributing
1244
+ This project follows Test Double's [code of
1245
+ conduct](https://testdouble.com/code-of-conduct) for all community interactions,
1246
+ including (but not limited to) one-on-one communications, public posts/comments,
1247
+ code reviews, pull requests, and GitHub issues. If violations occur, Test Double
1248
+ will take any action they deem appropriate for the infraction, up to and
1249
+ including blocking a user from the organization's repositories.
34
1250
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/searls/test_data.