test_data 0.0.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.