Minitest::Substitute
Simple Minitest helper to replace values such as an instance variable of an object or an environment variable for the duration of a block or a group of tests.
This comes in very handy when you have to derive from default configuration in order to test some aspects of your code.
- Homepage
- API
- Author: Sven Schwyn - Bitcetera
Install
This gem is cryptographically signed in order to assure it hasn’t been tampered with. Unless already done, please add the author’s public key as a trusted certificate now:
gem cert --add <(curl -Ls https://bitcetera.com/downloads/gem-public_cert.pem)
Add the following to the Gemfile or gems.rb of your Bundler powered Ruby project:
ruby
gem 'minitest-substitute'
And then install the bundle:
bundle install --trust-policy MediumSecurity
Finally, require this gem in your test_helper.rb
or spec_helper.rb
:
ruby
require 'minitest/substitute'
Update from 0.x.x to 1.x.x
Rails 7 has polluted Object
for everybody by introducing Object#with
. To prevent collisions, Minitest::Substitute has switched from with
to substitute
as of version 1.0.0.
After having updated this gem, you’ll have to adapt all your tests accordingly:
```ruby # Version 0.x.x with ‘@version’, 2, on: config do config.instance_variable_get(‘@version’) # => 2 end
Version 1.x.x
substitute ‘@version’, 2, on: config do config.instance_variable_get(‘@version’) # => 2 end ```
Usage
Block
To substitute the value of an instance variable for the duration of a block:
```ruby class Config def initialize @version = 1 end end
config = Config.new
config.instance_variable_get(‘@version’) # => 1 substitute ‘@version’, 2, on: config do config.instance_variable_get(‘@version’) # => 2 end config.instance_variable_get(‘@version’) # => 1 ```
:warning: The target on
is set explicitly in this case. If you omit this argument, self
will be used as target by default.
Class variables can be substituted as well:
```ruby class Config @@counter = 0 end
Config.class_variable_get(‘@@counter’) # => 0 substitute ‘@@counter’, 42, on: Config do Config.class_variable_get(‘@@counter’) # => 42 end Config.class_variable_get(‘@@counter’) # => 0 ```
Same goes for global variables:
ruby
$verbose = false # => false
substitute '$verbose', true do
$verbose # => true
end
$verbose # => false
And it works for globals like ENV
as well which comes in handy when you have to temporarily override the value of an environment variable:
ruby
ENV['EDITOR'] # => 'vi'
substitute "ENV['EDITOR']", 'nano' do
ENV['EDITOR'] # => 'nano'
end
ENV['EDITOR'] # => 'vi'
You can even substitute constants, however, you have to use their absolute name starting with ::
:
```ruby module Animals DOG_MAKES = ‘woof’ CAT_MAKES = ‘meow’ end
Animals::DOG_MAKES # => ‘woof’ substitute ‘::Animals::DOG_MAKES’, Animals::CAT_MAKES do Animals::DOG_MAKES # => ‘meow’ end Animals::DOG_MAKES # => ‘woof’ ```
Remember that class declarations are assigned to constants as well:
```ruby class Dog self.makes ‘woof’ end end
class Cat self.makes ‘meow’ end end
Dog.makes # => ‘woof’ substitute ‘::Dog’, Cat do Dog.makes # => ‘meow’ end Dog.makes # => ‘woof’ ```
It’s safe to nest multiple substitute
statements.
Group of Tests
When using spec notation, you can change a value for all tests within a describe
group:
```ruby class Config def initialize @version = 1 end end
describe Config do subject do Config.new end
describe ‘original version’ do it “returns the original version” do _(subject.instance_variable_get(‘@version’)).must_equal 1 end end
describe ‘sustituted version’ do substitute ‘@version’, 2, on: Config
it "returns the substituted version" do
_(subject.instance_variable_get('@version')).must_equal 2
end end end ```
:warning: The target on
is set explicitly in this case. If you omit this argument, :subject
will be used as target by default which refers to the subject defined by the subject {}
helper.
Alternatively, you can pass the substitution value as a block. This block will be evaluated once in the context of the test, in other words, you can use assignments done with let
inside the block:
```ruby class Config def initialize @version = 1 end end
describe Config do subject do Config.new end
let :version do 2 end
describe ‘original version’ do it “returns the original version” do _(subject.instance_variable_get(‘@version’)).must_equal 1 end end
describe ‘sustituted version’ do substitute ‘@version’, on: Config do version # set using “let” above end
it "returns the substituted version" do
_(subject.instance_variable_get('@version')).must_equal 2
end end end ```
If both a substitution value and a substitution block are present, the latter takes precedence.
It’s safe to use multiple substitute
statements within one describe
block.
(The spec integration is borrowed from minitest-around for elegance and compatibility.)
Development
To install the development dependencies and then run the test suite:
bundle install
bundle exec rake # run tests once
bundle exec guard # run tests whenever files are modified
You’re welcome to submit issues and contribute code by forking the project and submitting pull requests.
License
The gem is available as open source under the terms of the MIT License.