Giter Site home page Giter Site logo

bogus's Introduction

Bogus

Bogus aims to make your unit tests more reliable by ensuring that you don't stub or mock methods that don't actually exist in the mocked objects.

build status Code Climate Coverage Status Gem Version Dependency Status githalytics.com alpha

Example

class PostRepository
  def store(title)
    # save a new post in the database
  end
end

class PostAdder < Struct.new(:post_repository)
  def add(title)
    post = post_repository.store(title)
    # do some stuff with the post
  end
end

require 'bogus/rspec'

describe PostAdder do
  fake(:post_repository)

  it "stores the post" do
    post_adder = PostAdder.new(post_repository)
    
    post_adder.add("Bogus is safe!")

    expect(post_repository).to have_received.store("Bogus is safe!")
  end
end

Features

  • Safe Stubbing - Bogus does not allow you to stub methods that don't exist or don't match the stubbed signature.
  • Fakes - test doubles that have the same interface as the doubled class.
  • Support for ActiveRecord models - Bogus comes with support for active record fields out of the box.
  • Global fake configuration - Decouple your fakes from class names and define default return values in one place.
  • Contract tests - a unique feature of Bogus, which reduces the need for integrated tests to a minimum by ensuring that the things you stub match how the object really behaves.

Documentation

You can find more detailed (and executable) documentation on Relish.

License

MIT. See the LICENSE file.

Authors

bogus's People

Contributors

chastell avatar clemenshelm avatar durrantm avatar indrekj avatar ktdreyer avatar michalmuskala avatar psyho avatar voidlock avatar wrozka avatar yundt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bogus's Issues

Fakes shouldn't return themselves by default

All fake methods return self by default. It enables spying by default, but may lead to hard to debug errors.

For example when client is stubbed with:

stub(client).foo(1) { 'ABC' }

and then used:

client.foo(a).downcase

For a = 1 it will return the correct value, but for a = 2 it is going to fail with undefined method downcase for client. It has to fail in a friendlier way.

Fakes should return something like Bogus::DefaultReturnValue that would make clear, that the method was called on a wrong return value.

Argument requirements on .new

Given

class TestClass
  def initialize(foo, bar)
  end
end

I would expect

stub(TestClass).new(1) { fake(:test_class) }

to throw an error, because TestClass can't instantiate with only one argument. It doesn't. Is this because it's sidestepping #initialize, where the arguments are actually defined?

Implement fake_const(SomeConst)

Let's assume that in the production code there is a constant defined like this:

UserValidator = Validator.new do
  # ...
end

We want to be able to fake this object (copy it's entire interface):

fake(:user_validator, as: :object)

and we want to be able to replace the constant with a fake object that has the same exact interface:

fake_const(UserValidator)

Standard library parameters verification fails

I recently had an issue using Bogus when trying to mock Object.const_get { Array } without specifying any parameter.I had specs passing with ruby and jrbuy but failling with rbx. I later figured out that this should not work at all (https://www.relishapp.com/bogus/bogus/docs/safe-stubbing) since const_get take two parameters but strangely it works with ruby and jruby. The reason is that Object.method(:const_get).parameters returns [[:req, :name], [:opt, :inherit]] on rbx but [[:rest]] on ruby and jruby. So Bogus assumes that it takes any number of parameters which should not be the case since Object.const_get(:Array, true, 1) would raise an ArgumentError. I tried with different methods of Object and it seems that every method that take an optional parameter would behave the same way. I assume that this may be the case with any standard library method that takes an optional argument.

Any way to make transition from vanilla RSpec easier?

If you add Bogus, you lose RSpec's double, and the syntax for stub changes. Is there any way of incrementally adding Bogus to an existing codebase?

We're on RSpec 2.14 with no deprecation warnings, so all our test doubles are instantiated with double() (stub/mock are deprecated), but we do have a bunch of object.stub(method: result). This means that (for us) Bogus' stub(object).method { result } should not conflict as long as we can keep object.stub working as in rspec_mocks.

Unfriendly output on expectation failure

Here's an example..it seems like this expectation doesn't have a good to_s version of itself, as this is pretty unreadable

       Expected #<#<Class:0x007fa98af43810>:0x007fa98af62288 @__shadow__=#<Bogus::Shadow:0x007fa98af62148 @calls=[#<struct Bogus::Interaction method=:auction_ended_with_winner, args=[#<#<Class:0x007fa98afa25b8>:0x007fa98c40ff50 @__shadow__=#<Bogus::Shadow
:0x007fa98c40ff28 @calls=[#<struct Bogus::Interaction method=:id, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bogus::Interaction method=:end_time, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bogus::Interaction metho
d=:end, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bogus::Interaction method=:has_high_bidder?, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bogus::Interaction method=:method_missing, args=[:stub, :has_high_bidder?]
, return_value=nil, error=nil, has_result=nil>], @stubs=[], @required=#<Set: {}>>>], return_value=nil, error=nil, has_result=nil>], @stubs=[], @required=#<Set: {}>>> to have received auction_ended_no_bids(#<#<Class:0x007fa98afa25b8>:0x007fa98c40ff50 @__sh
adow__=#<Bogus::Shadow:0x007fa98c40ff28 @calls=[#<struct Bogus::Interaction method=:id, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bogus::Interaction method=:end_time, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bo
gus::Interaction method=:end, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bogus::Interaction method=:has_high_bidder?, args=[], return_value=nil, error=nil, has_result=nil>, #<struct Bogus::Interaction method=:method_missing, args=[:st
ub, :has_high_bidder?], return_value=nil, error=nil, has_result=nil>], @stubs=[], @required=#<Set: {}>>>), but it didn't.

This results from expecting messages on fakes.

  let(:listener) { fake(NotificationListener)}
      it "publishes an ended_no_bids event" do
        listener.should have_received.auction_ended_no_bids(auction)
      end

Any ideas if something unexpected is happening here? I could dig in and fix this..just want to know if maybe the usage is not anticipated?

Support double splat

Fake's method calls have to fail in the same way as in real objects, in order to achieve that, we'll have to support double splat to do that.

Fake class and classes in namespace

I have a problem with the library DCell. DCell provide DCell class where you can execute methods like start or setup. I would like to fake this class. I can do this by:

fake_class(DCell)

But after that I'm not able to use DCell::Node class.

How to reproduce:

require 'dcell'

require 'rspec'
require 'bogus/rspec'

describe DCell do
  fake_class(DCell)

  it "should have access to DCell subclass" d
    DCell::Node.new.should be_kind_of(Object)   
  end
end

And execute:

Failures:

  1) DCell should have access to DCell subclass
     Failure/Error: DCell::Node.new.should be_kind_of(Object)
     NameError:
       uninitialized constant DCell::Node
     # ./dcell_spec.rb:10:in `block (2 levels) in <top (required)>'

Finished in 0.01282 seconds
1 example, 1 failure

Stubbing on frozen fakes

Stubbing on frozen fakes is impossible if they were frozen before anything was stubbed. We need to create Shadow as soon as fake is created.

Using test spies in bogus

I'm trying to compare using bogus to rspec-mocks and I've run into an issue with test spies:

require 'spec_helper'

class PushNotifier
  def notify_async(messages)
  end
end

class CommentAdder
  def initialize(notifier)
    @notifier = notifier
  end

  def add(comment)
    # do some database stuff here...
    @notifier.notify_async("Comment: '#{comment}' added.")
  end
end

describe CommentAdder, '#add' do
  context 'bogus' do
    it "send push notifications when comment is added" do
      push_notifier = fake(:push_notifier, notify_async: true)

      CommentAdder.new(push_notifier).add("Hello world!")

      expect(push_notifier).to have_received(:notify_async).with("Comment: 'Hello world!' added.")
    end
  end

  context 'rspec-mocks' do
    it "send push notifications when comment is added" do
      push_notifier = double(notify_async: true)

      CommentAdder.new(push_notifier).add("Hello world!")

      expect(push_notifier).to have_received(:notify_async).with("Comment: 'Hello world!' added.")
    end
  end
end

Then the console output from RSpec looks like this:

:!rspec spec/bogus_spies_spec.rb
F.

Failures:

  1) CommentAdder#add bogus send push notifications when comment is added
     Failure/Error: expect(push_notifier).to have_received(:notify_async).with("Comment: 'Hello world!' added.")
       #<PushNotifier:0x3fd569f46cfc> expected to have received notify_async, but that method has not been stubbed.
     # ./spec/bogus_spies_spec.rb:26:in `block (3 levels) in <top (required)>'

Finished in 0.00737 seconds
2 examples, 1 failure

Failed examples:

rspec ./spec/bogus_spies_spec.rb:21 # CommentAdder#add bogus send push notifications when comment is added

shell returned 1  

Is there something simple I'm missing with the syntax here?

Celluloid actors

I have problem with Bogus and Celluloid. Bogus expects that Method object will be respond to name method. But Celluloid::Method does not respond for this method.

How to reproduce:

# celluloid_spec.rb
class Actor
  include Celluloid

  def test_method
    puts "hello"
  end
end

require 'rspec'
require 'bogus/rspec'

describe Actor do
  fake(:actor)

  before { stub(subject).test_method { "value" } } 

  it "returns value" do
    subject.test_method.should == "value"
  end
end

And we can execute spec for that

Failures:

  1) Actor returns value
     Failure/Error: before { stub(subject).test_method { "value" } }
     NoMethodError:
       undefined method `name' for #<Celluloid::Method Actor#test_method>
     # ./celluloid_method.rb:17:in `block (2 levels) in <top (required)>'

Finished in 0.00818 seconds
1 example, 1 failure

I created workaround for that: https://github.com/LTe/dht/blob/master/spec/support/celluloid_method.rb

Solutions:

  1. Create pull request to celluloid.
  2. Bogus should display information about problem with method object.
  3. Add information to wiki about - how to test celluloid actors.

RSpec described_class and verify_contract problems

When using verify_contract in a test for a class, using described_class doesn't work anymore because the returned value still refers to the original class and not the proxy object.

require 'bogus/rspec'

class Engine
  def start
  end
end

class Car < Struct.new(:engine)
  def start
    engine.start
  end
end

describe Car do
  fake(:engine)

  let(:car) { Car.new(engine) }

  describe '#start' do
    it 'starts the engine' do
      car.start

      expect(engine).to have_received.start
    end
  end
end

describe Engine do
  verify_contract(:engine)

#  let(:engine) { Engine.new }
  let(:engine) { described_class.new }

  describe '#start' do
    it 'returns true' do
      expect(engine.start).to be_nil
    end
  end
end

The above code throws the following error. When Engine is used instead of described_class it works.

$ rspec /tmp/bogus-repro.rb 
..

Finished in 0.00706 seconds
2 examples, 0 failures
/.rvm/gems/ruby-1.9.3-p448/gems/bogus-0.1.0/lib/bogus/verifies_contracts.rb:14:in `verify': Contract not fullfilled for engine! (Bogus::ContractNotFulfilled)

Missed interactions:
  - #start()

Actual interactions:

    from /.rvm/gems/ruby-1.9.3-p448/gems/bogus-0.1.0/lib/bogus/public_methods.rb:8:in `verify_contract!'
    from /.rvm/gems/ruby-1.9.3-p448/gems/bogus-0.1.0/lib/bogus/rspec_extensions.rb:19:in `block (2 levels) in verify_contract'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:470:in `instance_eval'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:470:in `instance_eval_with_rescue'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:31:in `run'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `block in run'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `each'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:66:in `run'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/hooks.rb:418:in `run_hook'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:30:in `block in run'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/reporter.rb:34:in `report'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/command_line.rb:25:in `run'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/runner.rb:80:in `run'
    from /.rvm/gems/ruby-1.9.3-p448/gems/rspec-core-2.13.1/lib/rspec/core/runner.rb:17:in `block in autorun'

Not sure if this can be fixed in a nice way, but at least a warning in the documentation would be nice.

Module#=== monkey patch breaks BasicObject#instance_eval on Rbx

The monkey patch for Module#=== included in Bogus

class Module
  Bogus::Support.supress_warnings do
    def ===(object)
      object.kind_of?(self)
    end
  end
end

Breaks BasicObject#instance_eval on Rubinius.

class Foo < BasicObject
  def x
    3
  end
end

Foo.new.instance_eval do
  Kernel.puts x
end

# On MRI:
#
#      3
#
# On Rubinius:
#
# An exception occurred running /home/arne/projects/ruby-tmp/00205.rb:
#
#     Unable to send 'kind_of?' on instance of BasicObject (NoMethodError)
#
# Backtrace:
#
#   BasicObject(Foo)#kind_of? (method_missing) at kernel/common/basic_object.rb:3
#                                   Module#=== at /home/arne/projects/ruby-tmp/00205.rb:3
#               BasicObject(Foo)#instance_eval at kernel/common/eval.rb:24
#                            Object#__script__ at /home/arne/projects/ruby-tmp/00205.rb:13
#             Rubinius::CodeLoader#load_script at kernel/delta/code_loader.rb:66
#             Rubinius::CodeLoader.load_script at kernel/delta/code_loader.rb:152
#                      Rubinius::Loader#script at kernel/loader.rb:649
#                        Rubinius::Loader#main at kernel/loader.rb:825

This is because Rubinius's instance_eval calls Module#===

  def instance_eval(string=nil, filename="(eval)", line=1, &prc)
    if ::ImmediateValue === self
      sc = nil
    else
      sc = ::Rubinius::Type.object_singleton_class(self)
    end
    # ... snip

Stub an instance of a class as a constant

It seems when you add in bogus, it won't let you call RSpec methods anymore? If that's so, I'm okay with that, but there's one feature that is missing that's rather important with my unit tests.

I have a constant that is an instance of an ActiveMerchant gateway, is there a way I can stub that so I can test?

Fake's __copied_class__ is missing causing crash when running Mutant

/home/vagrant/.gem/ruby/1.9.3/gems/bogus-0.1.0/lib/bogus/fake.rb:39:in `name': undefined method `name' for nil:NilClass (NoMethodError)
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/matcher/namespace.rb:64:in `emit_scope'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/matcher/namespace.rb:51:in `block in scopes'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/matcher/namespace.rb:50:in `each_object'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/matcher/namespace.rb:50:in `each'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/matcher/namespace.rb:50:in `scopes'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/matcher/namespace.rb:21:in `each'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/matcher/namespace.rb:21:in `each'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/cli/classifier.rb:94:in `each'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/config.rb:22:in `subjects'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/runner/config.rb:61:in `each'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/runner/config.rb:61:in `map'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/runner/config.rb:61:in `run_subjects'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/runner/config.rb:75:in `run'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/runner.rb:26:in `initialize'
        from /home/vagrant/.gem/ruby/1.9.3/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
        from /home/vagrant/.gem/ruby/1.9.3/gems/abstract_type-0.0.5/lib/abstract_type.rb:40:in `new'
        from /home/vagrant/.gem/ruby/1.9.3/gems/adamantium-0.0.8/lib/adamantium/class_methods.rb:17:in `new'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/support/method_object.rb:29:in `run'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/lib/mutant/cli.rb:26:in `run'
        from /home/vagrant/.gem/ruby/1.9.3/bundler/gems/mutant-f3a2e42f70c5/bin/mutant:18:in `<top (required)>'
        from /home/vagrant/.gem/ruby/1.9.3/bin/mutant:19:in `load'
        from /home/vagrant/.gem/ruby/1.9.3/bin/mutant:19:in `<main>'
        from /home/vagrant/.gem/ruby/1.9.3/bin/ruby_noexec_wrapper:14:in `eval'
        from /home/vagrant/.gem/ruby/1.9.3/bin/ruby_noexec_wrapper:14:in `<main>'

It's hard for me to figure it out but it seems like mutant tries to mutate a class that was copied by bogus' fake but in the moment it's happening that fake is not fully setup.

I have no idea how to solve this :/ Maybe it's mutant kicking in too early, maybe it's bogus being in a weird broken state? Please HALP ;)

Contract test failures are not clear

The test output is not "clear" that a contract test failed, by looking only at the final output of rspec:

3 examples, 0 failures

https://www.relishapp.com/bogus/bogus/docs/contract-tests/contract-tests-with-mocks#fails-when-mocked-methods-are-not-called-on-real-object

I get an exit code 1 when I run rspec, and the output says that contracts aren't fulfilled, but it doesn't actually says that there are any failed examples.

$ rspec; echo "exitcode: $?"                                                                                                                                                                                                                               ‹ruby-2.3.0›
...
An error occurred in an `after(:suite)` hook.
Failure/Error: raise Bogus::ContractNotFulfilled.new(fake_name, missed: missed, actual: actual)

Bogus::ContractNotFulfilled:
  Contract not fullfilled for library!

  Missed interactions:
    - #has_book?("Moby Dick") => true

  Actual interactions:
    - #return("Moby Dick") => []
    - #checkout("Moby Dick") => "Moby Dick"
    - #has_book?("Moby Dick") => false
# /Users/wes/.rvm/gems/ruby-2.3.0/gems/bogus-0.1.6/lib/bogus/contracts/verifies_contracts.rb:14:in `verify'
...

3 examples, 0 failures

exitcode: 1

If I wasn't paying attention to the exit code, I would not have noticed this failed test.

ActiveRecord::AssociationTypeMismatch

I have the following test:

describe Comment do
    fake(:user) { User }
    let(:comment) { Comment.new(user: user) }

    it "has a user" do
        expect(comment.user).to eq(user)
    end
end

As I am testing comment I don't want it to be a fake, but user I would like to be a fake.

Rspec fails with:

ActiveRecord::AssociationTypeMismatch:
   User(#70251274274320) expected, got User(#70251274343580)

Not sure if this should work or I should try to do things differently. Thanks.

Crashes on Rubinius

getting for example this when running on rbx:

2) ROM::Session::Mapper#load when IM does not include the loaded object returns a newly loaded object
     Failure/Error: let(:loader) { fake(:loader) { ROM::Mapper::Loader } }
     SyntaxError:
       (eval):1: expecting ')'
     # /Users/solnic/.rvm/rubies/rbx-2.0.0/runtime/19/melbourne.rbc:81:in `syntax_error'
     # /Users/solnic/.rvm/rubies/rbx-2.0.0/runtime/19/melbourne.rbc:88:in `parse_string'
     # /Users/solnic/.rvm/rubies/rbx-2.0.0/runtime/19/compiler/stages.rbc:241:in `parse'
     # /Users/solnic/.rvm/rubies/rbx-2.0.0/runtime/19/compiler/stages.rbc:207:in `run'
     # /Users/solnic/.rvm/rubies/rbx-2.0.0/runtime/19/compiler/compiler.rbc:374:in `run'
     # /Users/solnic/.rvm/rubies/rbx-2.0.0/runtime/19/compiler/compiler.rbc:302:in `compile_eval'
     # /Users/solnic/.rvm/rubies/rbx-2.0.0/runtime/19/compiler/compiler.rbc:314:in `construct_block'
     # kernel/common/eval19.rb:61:in `instance_eval'
     # kernel/bootstrap/array.rb:68:in `each'
     # kernel/bootstrap/array.rb:68:in `each'
     # ./spec/unit/rom/session/mapper_spec.rb:6:in `__script__'
     # kernel/common/hash19.rb:257:in `fetch'
     # ./spec/unit/rom/session/mapper_spec.rb:32:in `__script__'
     # kernel/common/eval19.rb:45:in `instance_eval'
     # kernel/bootstrap/array19.rb:18:in `map'
     # kernel/bootstrap/array19.rb:18:in `map'
     # kernel/bootstrap/array19.rb:18:in `map'
     # kernel/loader.rb:697:in `run_at_exits'
     # kernel/loader.rb:717:in `epilogue'
     # kernel/loader.rb:850:in `main'

I'm not sure if you plan to support rubinius but I'd say you should...otherwise bogus won't be an option for A LOT of library authors :/

Stub new method on a class

I'm trying to stub the new method on a class, but cannot figure out how to do that. All in all, I want to return an object that is stubbed, so I can check to see in my controller (Rails project) what the responses will be if it can or cannot be saved.

Here's what I have tried, but are no use:

fake(:company, as: :instance) { Company }
fake(:company_class, new:company, as: :class) { Company }

Faking active_record classes

I have issue with faking active record "where" method.
An example:

class User < ActiveRecord::Base
end

class Task < ActiveRecord::Base
end

class ListTasks
  def initialize(user , task_repository = Task)
    @user = user
    @task_repository = task_repository
  end

  def all
    @task_repository.where(user_id: @user.id).order_by("priority asc")
  end
end

describe ListTasks do
  fake(:user, id: 100)
  fake(:task_repository) { Task }
  let(:subject) { described_class.new(user, task_repository) }

  it "fetches tasks for a given user" do
    subject.all
    expect(task_repository).to have_received.where(user_id: 100)
  end
end

Executing rspec gives:

Task:0x1d65a50 does not respond to where

I am using bogus v0.0.4.

Entity return values and contracts

So I have service objects which have methods that return new entities - builders are a good example. However, if I stub out that service object to return a fake of the class it's supposed to return (or even a blank instance of the same class!) when I verify the contract it says it failed.

I can sort of understand why - but I'm concerned that forcing me to return nicely equivalent entities will result in complicated collaboration testing.

RSpec 3 Shared Examples Support

Not sure if this is specific to RSpec 3 - I'm trying to use Bogus and have two classes that have similar contracts (as one's a subclass of another). I'd normally put these in a shared example group and run those contract tests on both - but when I do that, Bogus doesn't pick up that the methods ran. Thoughts?

Spying on object creation gets "undefined method should"

ruby 1.9.3-p194
bogus 0.1.4
minitest 4.7.5

No other gems are being loaded.

describe SoapRequestBuilder::RequestBuilder do
  fake_class(SoapRequestBuilder::BodyBuilder)

  describe "#body" do
    it "lets SoapRequestBuilder::BodyBuilder do the work" do
      @model = Person.new
      SoapRequestBuilder::RequestBuilder.new(@model).body
      SoapRequestBuilder::BodyBuilder.should have_received.new(@model)
    end
  end
end

Running this gives me

NoMethodError: undefined method `should' for SoapRequestBuilder::BodyBuilder:Class

Not sure if this is a Bogus problem or a problem with my setup.

#send

Should calls to #send(:method, args) be recorded as if you called .method(args), for purposes of verifying contracts? Trying to de-duplicate some common accessor code, and I can't do it without eval.

RSpec methods not overriden

When trying to stub a method on an object like so:

stub(object).bar { 42 }

the RSpec's own stub method is being called, not the Bogus'. I guess, when I require bogus/rspec in spec_helper it includes the Bogus::MockingDSL, but the RSpec itself is lower in the ancestor chain, so it overrides the methods with coinciding names.

The Bogus.create_stub call works just fine.

Add support for checking arguments with proc

RSpec lets you do this:

library.should_receive(:checkout).with{|c| c.bytesize == 9 }.and_return(:checked_out)

Would be cool to have it supported in bogus:

describe Library do
  it "does something" do
    library = Library.new
    stub(library).checkout(with{|c| c.bytesize == 9 }) { :checked_out }
    library.checkout("some book").should == :checked_out
  end
end

Can't stub to_s on a fake

fake(to_s: "fafarafa").to_s #=> "#<Bogus::RespondsToEverything:0x00000014479e38>" while I'd expect it to be "fafarafa"

It happens regardles it's an anonymous or existing class fake.

Contract tests with stubbed methods of real objects

Using bogus I can stub a method on real object:

user = FactoryGirl.create(:user)
stub(user).friend?(5) { true }

And this works great! However, I would like to use contract tests in such a case. I went through the whole documentation and couldn't find any related example.

Ideally it should work like:

user = fake(:user, FactoryGirl.create(:user)) # creates a named fake from existing object
stub(user).friend?(5) { true }

# in spec/models/user_spec.rb
verify_contract(:user)

Can you show me how to achieve this if it's possible? Or if it's not possible - does it sound like a reasonable feature request?

Bogus causing errors on factory girl/rbx-2.2.7 setup

Hi getting errors on adding factory_girl with bogus on a rbx-2.2.7:

rbx-2.2.7 :003 > FactoryGirl.build :category
ArgumentError: method 'kind_of?': given 1, expected 0
    from /Users/Ace/.rvm/gems/rbx-2.2.7@cr/gems/factory_girl-4.4.0/lib/factory_girl/decorator.rb:10:in `kind_of? (method_missing)'
    from /Users/Ace/.rvm/gems/rbx-2.2.7@cr/gems/factory_girl-4.4.0/lib/factory_girl/decorator.rb:14:in `send'
    from /Users/Ace/.rvm/gems/rbx-2.2.7@cr/gems/factory_girl-4.4.0/lib/factory_girl/decorator.rb:10:in `method_missing'
    from /Users/Ace/.rvm/gems/rbx-2.2.7@cr/gems/factory_girl-4.4.0/lib/factory_girl/decorator/invocation_tracker.rb:11:in `kind_of? (method_missing)'
    from /Users/Ace/.rvm/gems/rbx-2.2.7@cr/gems/factory_girl-4.4.0/lib/factory_girl/decorator.rb:14:in `send'
    from /Users/Ace/.rvm/gems/rbx-2.2.7@cr/gems/factory_girl-4.4.0/lib/factory_girl/decorator.rb:10:in `kind_of? (method_missing)'
    from /Users/Ace/.rvm/gems/rbx-2.2.7@cr/gems/bogus-0.1.5/lib/bogus/core_ext.rb:19:in `==='

License missing from gemspec

Some companies will only use gems with a certain license.
The canonical and easy way to check is via the gemspec
via e.g.

spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']

There is even a License Finder to help companies ensure all gems they use
meet their licensing needs. This tool depends on license information being available in the gemspec.
Including a license in your gemspec is a good practice, in any case.

How did I find you?

I'm using a script to collect stats on gems, originally looking for download data, but decided to collect licenses too,
and make issues for missing ones as a public service :)
https://gist.github.com/bf4/5952053#file-license_issue-rb-L13 So far it's going pretty well

bogus uses deprecated Rspec configuration options

DEPRECATION: RSpec::Core::Configuration#backtrace_clean_patterns is deprecated. 
Use RSpec::Core::Configuration#backtrace_exclusion_patterns instead. 
Called from .rbenv/versions/2.0.0-p0/lib/ruby/gems/2.0.0/gems/
bogus-0.1.1/lib/bogus/rspec.rb:8:in `block in <top (required)>'.

Spying on setter methods doesn't work

When I call a method on my object, one of the object's collaborator's attributes will change. I wanted to test this exchange by spying on the attribute's setter method, i.e. #baz=. But since the usual have_received(:baz=) doesn't work (#40), I have to verify the expectation via have_received.baz=(any_args) which yields false positives all the time.

A working example with false positives:

require 'rubygems'
require 'rspec'
require 'bogus/rspec'

class Bar
  def baz=(x); end
end

class Foo
  attr_reader :barable
  def initialize(barable)
    @barable = barable
  end

  def forward_something(x)
    # barable.baz = x # disable to see whether the expectation works
  end
end

describe Foo do
  fake(:bar)
  it "forwards setting something" do
    foo = Foo.new(bar)
    foo.forward_something(:stuff)

    expect(bar).to have_received.baz=(any_args)
  end
end

Problems with FactoryGirl/Shoulda Matchers and UndefinedReturnValue

Hi,

I'm seeing intermittent UndefinedReturnValue errors. They seem to occur depending on what order the tests are run. For example:

1__matthews-macbook-pro__tmux_

On other occasions the tests fail with the same error, but from shoulda-matchers instead:

1__matthews-macbook-pro__tmux_

On very rare occasions the suite passes. There's nothing much in my bogus config:

Bogus.configure do |config|
  config.fake_ar_attributes = true
end

Any idea what's going on here?

Make Bogus work with RSpec < 2.14

We fixed the deprecation warning, but it broke Bogus on old RSpec versions.

/home/vagrant/.gem/ruby/1.9.3/gems/bogus-0.1.2/lib/bogus/rspec.rb:8:in `block in <top (required)>': undefined method `backtrace_exclusion_patterns' for #<RSpec::Core::Configuration:0x0000000131d480> (NoMethodError)

Fake replying that it does not respond to method when it does

I have this code:

describe Branch do
  fake(:branch)
  fake(:company)
  it "should get it's max users from it's company" do
      stub(branch).company { company }
      p (Company.new).respond_to? :max_users
      stub(company).max_users { 25 }
      expect_that { branch.max_users == 25 }
    end
end

I get this error:

Failure/Error: stub(company).max_users { 25 }
     NameError:
       #<#<Class:0x007f951f06a660>:0x007f951ee711b0 @__shadow__=#<Bogus::Shadow:0x007f951ee710c0 @calls=[], @stubs=[], @required=#<Set: {}>>> does not respond to max_users

The puts statement returns a true value, BTW, so I know that this is not a problem.

Using Zeus, Rails 4, Rspec-rail 2.14.0, latest bogus from rubygems.org.

Does not override the === operator

I have added a test (327fbc9) showing the failure. Typical use case can also be found in the commit message

Maybe there is a way to handle this already using the existing syntax. I could not find a solution in the docs though.

Compatibility with Shoulda-Matchers

I seem to have a problem when I include the latest shoulda-matchers (2.2.0) with Bogus (0.1.4). When I run the tests after adding in require 'bogus/rspec' in my spec_helper.rb.

When required:

Failure/Error: it { should belong_to(:shift) }
     NoMethodError:
       undefined method `belong_to' for #<RSpec::Core::ExampleGroup::Nested_12:0x007fa3ca51f610>

Proc argument matcher matches all or nothing

I am not able to use proc argument matcher to match just argument among a few:

mock(ESP::Mail).deliver("kiszonka", with { |message| message[:to] == "[email protected]" })

ESP::Mail.deliver "kiszonka", to: "[email protected]"

doesn't work and the matcher never gets called, while

mock(ESP::Mail).deliver(with { |template_name, message| 
 template_name == "kiszonka" && message[:to] == "[email protected]" })

ESP::Mail.deliver "kiszonka", to: "[email protected]"

works. Is it desired behavior and I'm just doing something wrong?

RSpec expectation compatibility

The spy-syntax is:

expect(obj).to have_received.foo(any_args)

RSpec's spies on the other hand work with

expect(obj).to have_received(:foo)

Keeping the latter in place after setting up bogus basically breaks spy-expectations without warning or any helpful message. What I did get was this:

ArgumentError:
       tried to stub foo(bar) with arguments: 

Didn't know what was wrong. So there are two issues, basically:

  1. add RSpec spy compatible expectation syntax,
  2. throw more meaningful messages.

It took some guesswork and granular comparison between examples is the GitHub README and my code to find out the error was on my side in the first place. Relishapp.com examples sport should syntax only.

Contract from documentation pass

I'm not able to reproduce example from documentation click

class Library
  def initialize
    @books = []
  end

  def has_book?(book)
    @books.include?(book)
  end

  def checkout(book)
    @books.delete(book)
  end

  def return(book)
    @books << book
  end
end

require 'rspec'
require 'bogus/rspec'

describe Library do
  verify_contract(:library)

  let(:library) { Library.new }

  it "marks books as unavailable after they are checked out" do
    library.return("Moby Dick")

    library.checkout("Moby Dick")

    library.has_book?("Moby Dick").should be_false
  end
end

Rspec output:

.

Finished in 0.00331 seconds
1 example, 0 failures

But documentation says: spec file with following content should fail

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.