Skip to content

featurist/strictly_fake

Repository files navigation

StrictlyFake Build status Gem Version

Sometimes fakes are a good choice. But the price is high. In particular, they make changing code harder. You rename a method, but all tests that stub the previous version keep passing. It would be nice if those started to fail so that when they're green again, you can be certain that everything that had to be updated was updated. Well, now you can.

To be fair, you already can in Rspec with their verifying double. But what about Minitest? And there are still differences. Unlike verifying double:

  • here you need to supply real objects to create fakes. That's controversial - as it goes against the idea of testing in isolation - but realistically, at least in Rails, everything is loaded anyway, so that's a moot point;
  • strictly_fake is aware of autogenerated methods (e.g. ActiveRecord model accessors);
  • strictly_fake does not stub constants (e.g. classes). You can, however, pass a fake to Minitest's Object#stub to achieve this (see example below);
  • strictly_fake performs a full parameter check, comparing required, optional and keyword arguments (veryfing double only checks arity afaik).

Installation

Add this line to your application's Gemfile:

gem 'strictly_fake'

And then execute:

$ bundle install

Usage

require 'strictly_fake'

# Given we don't want to actually pay in tests
class PaymentGateway
  def pay(recipient, amount, reference = nil);
    # calls remote payment provider...
  end
end

# We can use a fake instead
payment_gateway = StrictlyFake.new(PaymentGateway.new)

# Let's stub a method that _isn't_ defined in PaymentGateway:
payment_gateway.stub(:bar)
# => throws "Can't stub non-existent method PaymentGateway#bar (StrictlyFake::Error)"

# Let's stub an existing method, but with a wrong signature: 
payment_gateway.stub(:pay) { |amount| }
# => throws "Expected PaymentGateway#pay stub to accept (req, req, opt=), but was (req) (StrictlyFake::Error)"

# All good now!
payment_gateway.stub(:pay) { |recipient, amount, reference = nil| 'Success!' }

payment_gateway.pay('Dave', 10)
# => 'Success!'

# Makeshift mock
invoked = false
payment_gateway.stub(:pay) do |recipient, amount, reference = nil|
  # Further arguments check
  assert(amount.is_a?(Money))
  invoked = true
end

payment_gateway.pay('Dave', Money.new(10))
assert(invoked)
# => Pass

# Stubbing class methods is no different
time = StrictlyFake.new(Time)

time.stub(:now) { 'XYZ' }
time.now
# => 'XYZ'

# Combine with Minitest stub to actually stub constant
Time.stub :now, time.now do
  Time.now
  # => 'XYZ'
end

Note: Minitest is required for assert* to work.

Development

After checking out the repo, run bundle install to install dependencies. Then, run bundle exec rspec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

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 tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/featurist/strictly_fake.

License

The gem is available as open source under the terms of the MIT License.

About

Stub that automatically verifies that stubbed methods exist and the signatures match the original.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages