Skip to content

Commit

Permalink
Verifying null objects only respond to defined methods.
Browse files Browse the repository at this point in the history
* No additional documentation, since this is the least surprising
  behaviour.

Fixes rspec#392.
  • Loading branch information
xaviershay committed Sep 25, 2013
1 parent 331b4b3 commit 538f524
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Changelog.md
Expand Up @@ -26,6 +26,8 @@ Enhancements:
* Yield the receiver to `any_instance` implementation blocks (Sam Phippen).
* Provide `instance_double` and `class_double` to create verifying doubles,
ported from `rspec-fire` (Xavier Shay).
* `as_null_object` on a verifying double only responds to defined methods
(Xavier Shay).
* Improved performance of double creation, particularly those with many
attributes. (Xavier Shay)
* Default value of `transfer_nested_constants` option for constant stubbing can
Expand Down
12 changes: 12 additions & 0 deletions lib/rspec/mocks/verifying_double.rb
Expand Up @@ -4,11 +4,22 @@
module RSpec
module Mocks

module VerifyingDouble
def method_missing(message, *args, &block)
# Null object conditional is an optimization. If not a null object,
# validity of method expectations will have been checked at definition
# time.
__mock_proxy.ensure_implemented(message) if null_object?
super
end
end

# A mock providing a custom proxy that can verify the validity of any
# method stubs or expectations against the public instance methods of the
# given class.
class InstanceVerifyingMock
include TestDouble
include VerifyingDouble

def initialize(doubled_module, *args)
@doubled_module = doubled_module
Expand All @@ -32,6 +43,7 @@ def __build_mock_proxy
# constants to work.
class ClassVerifyingMock < Module
include TestDouble
include VerifyingDouble

def initialize(doubled_module, *args)
@doubled_module = doubled_module
Expand Down
2 changes: 0 additions & 2 deletions lib/rspec/mocks/verifying_proxy.rb
Expand Up @@ -58,8 +58,6 @@ def method_double
end
end

protected

def ensure_implemented(method_name)
@doubled_module.when_loaded do |original_module|
unless original_module.__send__(@method_checker, method_name)
Expand Down
14 changes: 14 additions & 0 deletions spec/rspec/mocks/verifying_double_spec.rb
Expand Up @@ -107,6 +107,13 @@ def prevents(&block)
o = instance_double(LoadedClass, :defined_instance_method => 1)
expect(o.defined_instance_method).to eq(1)
end

it 'only allows defined methods for null objects' do
o = instance_double('LoadedClass').as_null_object

expect(o.defined_instance_method).to eq(o)
prevents { o.undefined_method }
end
end
end

Expand Down Expand Up @@ -186,6 +193,13 @@ def prevents(&block)
expect(dbl1).to receive(:undefined_class_method)
}
end

it 'only allows defined methods for null objects' do
o = class_double('LoadedClass').as_null_object

expect(o.defined_class_method).to eq(o)
prevents { o.undefined_method }
end
end
end

Expand Down

0 comments on commit 538f524

Please sign in to comment.