1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
## Setting/Resetting the random seed
ffaker maintains its own random number generator which allows the responses to
be deterministic and repeatable given the correct seed.
You can get the current seed with `FFaker::Random.seed`, set it with
`FFaker::Random.seed=<seed>`, and reset it back to its initial state with
`FFaker::Random.reset!`. You can also use `FFaker::Random.rand` to get a random
number from the RNG.
```ruby
require 'ffaker'
> FFaker::Random.seed
# => 296167445578296242020083756344880134311
> FFaker::Random.seed=12345
# => 12345
> FFaker::Random.seed
# => 12345
> 5.times.map{ FFaker::Random.rand(0..9) }
# => [2, 5, 1, 7, 4]
> FFaker::Random.reset!
> 5.times.map{ FFaker::Random.rand(0..9) }
# => [2, 5, 1, 7, 4]
```
Calling `seed=` implicitly calls `reset!` so there is no need to call it
separately after setting the seed.
### Using the same random seed as your tests
If you are using Minitest or Rspec and run your tests in random order, ffaker
can use their random seed to return the same data given the same seed.
Note: ffaker can not use the random seed from Test::Unit because it [does not
allow the random seed to be set by the user](https://github.com/test-unit/test-unit/blob/master/lib/test/unit/test-suite-creator.rb#L67-L69).
#### Minitest
Assuming you're already using ffaker in your tests, you will need add a "plugin"
to make it use the same seed as Minitest. In your tests directory (usually named
"test") make another directory named "minitest" and create a file in that
directory named "ffaker_random_seed_plugin.rb" that contains:
```ruby
# test/minitest/ffaker_random_seed_plugin.rb
module Minitest
def self.plugin_ffaker_random_seed_init(options)
FFaker::Random.seed = options[:seed]
end
end
```
Next, you will need to add a `before_setup` method in every test file that uses
ffaker and call `FFaker::Random.reset!` within it. Ideally this will be in your
test case superclass.
```ruby
# test_helper.rb or similar.
class TestBase < Minitest::Test
def before_setup
FFaker::Random.reset!
end
end
class TestSomethingUsingFFaker < TestBase
def test_something_using_ffaker
# use FFaker as normal
end
end
```
ffaker will now use the same random seed as Minitest, including seeds passed in
using `--seed nnn` on the command line, and will return the same data every
time that seed is used.
#### Rspec
Assuming you're already using ffaker in your specs, add the following to your
`spec_helper.rb` or equivalent file:
```ruby
# spec_helper.rb
RSpec.configure do |config|
config.before(:all) { FFaker::Random.seed=config.seed }
config.before(:each) { FFaker::Random.reset! }
end
```
If your helper already has an `RSpec.configure` block, simply put the two
"config.before" lines in that block.
ffaker will now use the same random seed as Rspec, including seeds passed in
using `--seed nnn` on the command line, and will return the same data every
time that seed is used.
### Generating random data in ffaker modules
ffaker modules should use the included deterministic methods to get random data
so that the same data can be returned with the correct random seed. All ffaker
modules extend the ModuleUtils module which provides the necessary methods. They
are:
* Use `fetch_sample(array)` instead of `Array#sample` to get a random item from an array.
* Use `fetch_sample(array, count: n)` instead of `Array#sample(n)` to get multiple random items from an array.
* Use `shuffle(array)` instead of `Array#shuffle` to randomly reorder an array.
* Calls to `rand` will automatically use the correct random-number generator, no change is required.
For other uses, you can access the random number generator directly via
`FFaker::Random`. Example:
```ruby
array.shuffle!(random: FFaker::Random)
```
### Testing repeatability of ffaker modules
There are helper methods available to use in tests to ensure your module output
is repeatable and deterministic. All existing module tests use them, and we
would like all future modules to also use them.
First, include the DeterministicHelper in your test class:
```ruby
include DeterministicHelper
```
If your want to test methods that do not require arguments, the
`assert_methods_are_deterministic` method will help you test many methods with
one line of test.
```ruby
# Example: This will test the methods :method_name, :other_method_name, and
# :another_method_name on class FFaker::NewFFakerModule.
assert_methods_are_deterministic(
FFaker::NewFFakerModule,
:method_name, :other_method_name, :another_method_name
)
```
For testing methods that require an argument, or to test more complicated
behavior, you can use the `assert_deterministic` method within a test method.
```ruby
def test_some_method
assert_deterministic { FFaker::NewFFakerModule.some_method(:required_argument) }
end
```
For more examples, please see the test cases for existing modules.
|