Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add cukes for new stub_const feature.

Closes #144.
  • Loading branch information...
commit e31f4a46a88e2ef03b6c34cc33f06c9f5cb2b2e2 1 parent ecfb7f6
@myronmarston myronmarston authored
View
3  features/.nav
@@ -18,6 +18,9 @@
- explicit.feature
- general_matchers.feature
- type_matchers.feature
+- stubbing_constants:
+ - stub_defined_constant.feature
+ - stub_undefined_constant.feature
- outside_rspec:
- configuration.feature
- standalone.feature
View
62 features/stubbing_constants/README.md
@@ -0,0 +1,62 @@
+## Stubbing Constants
+
+Support is provided for stubbing constants. Like with method stubs, the
+stubbed constants will be restored to their original state when a method
+completes.
+
+``` ruby
+stub_const("Foo", fake_foo)
+Foo # => fake_foo
+```
+
+Stubbed constant names must be fully qualified; the current module
+nesting is not considered.
+
+``` ruby
+module MyGem
+ class SomeClass; end
+end
+
+module MyGem
+ describe "Something" do
+ let(:fake_class) { Class.new }
+
+ it "accidentally stubs the wrong constant" do
+ # this stubs ::SomeClass (in the top-level namespace),
+ # not MyGem::SomeClass like you probably mean.
+ stub_const("SomeClass", fake_class)
+ end
+
+ it "stubs the right constant" do
+ stub_const("MyGem::SomeClass", fake_class)
+ end
+ end
+end
+```
+
+When you stub a constant that is a module or a class, nested
+constants on the original module or class are not transferred
+by default, but you can use the `:transfer_nested_constants`
+option to tell rspec-mocks to transfer them:
+
+``` ruby
+class CardDeck
+ SUITS = [:Spades, :Diamonds, :Clubs, :Hearts]
+ NUM_CARDS = 52
+end
+
+fake_class = Class.new
+stub_const("CardDeck", fake_class)
+CardDeck # => fake_class
+CardDeck::SUITS # => raises uninitialized constant error
+CardDeck::NUM_CARDS # => raises uninitialized constant error
+
+stub_const("CardDeck", fake_class, :transfer_nested_constants => true)
+CardDeck::SUITS # => [:Spades, :Diamonds, :Clubs, :Hearts]
+CardDeck::NUM_CARDS # => 52
+
+stub_const("CardDeck", fake_class, :transfer_nested_constants => [:SUITS])
+CardDeck::SUITS # => [:Spades, :Diamonds, :Clubs, :Hearts]
+CardDeck::NUM_CARDS # => raises uninitialized constant error
+```
+
View
79 features/stubbing_constants/stub_defined_constant.feature
@@ -0,0 +1,79 @@
+Feature: Stub Defined Constant
+
+ Use `stub_const` to stub constants. When the constant is already defined,
+ the stubbed value will replace the original value for the duration of the
+ example.
+
+ Scenario: Stub top-level constant
+ Given a file named "stub_const_spec.rb" with:
+ """ruby
+ FOO = 7
+
+ describe "stubbing FOO" do
+ it "can stub FOO with a different value" do
+ stub_const("FOO", 5)
+ FOO.should eq(5)
+ end
+
+ it "restores the stubbed constant when the example completes" do
+ FOO.should eq(7)
+ end
+ end
+ """
+ When I run `rspec stub_const_spec.rb`
+ Then the examples should all pass
+
+ Scenario: Stub nested constant
+ Given a file named "stub_const_spec.rb" with:
+ """ruby
+ module MyGem
+ class SomeClass
+ FOO = 7
+ end
+ end
+
+ module MyGem
+ describe SomeClass do
+ it "stubs the nested constant when it is fully qualified" do
+ stub_const("MyGem::SomeClass::FOO", 5)
+ SomeClass::FOO.should eq(5)
+ end
+ end
+ end
+ """
+ When I run `rspec stub_const_spec.rb`
+ Then the examples should all pass
+
+ Scenario: Transfer nested constants
+ Given a file named "stub_const_spec.rb" with:
+ """ruby
+ module MyGem
+ class SomeClass
+ FOO = 7
+ end
+ end
+
+ module MyGem
+ describe SomeClass do
+ let(:fake_class) { Class.new }
+
+ it "does not transfer nested constants by default" do
+ stub_const("MyGem::SomeClass", fake_class)
+ expect { SomeClass::FOO }.to raise_error(NameError)
+ end
+
+ it "transfers nested constants when using :transfer_nested_constants => true" do
+ stub_const("MyGem::SomeClass", fake_class, :transfer_nested_constants => true)
+ SomeClass::FOO.should eq(7)
+ end
+
+ it "can specify a list of nested constants to transfer" do
+ stub_const("MyGem::SomeClass", fake_class, :transfer_nested_constants => [:FOO])
+ SomeClass::FOO.should eq(7)
+ end
+ end
+ end
+ """
+ When I run `rspec stub_const_spec.rb`
+ Then the examples should all pass
+
View
50 features/stubbing_constants/stub_undefined_constant.feature
@@ -0,0 +1,50 @@
+Feature: Stub Undefined Constant
+
+ Use `stub_const` to stub constants. When the constant is not already defined,
+ all the necessary intermediary modules will be dynamically created. When the
+ example completes, the intermediary module constants will be removed to return
+ the constant state to how it started.
+
+ Scenario: Stub top-level constant
+ Given a file named "stub_const_spec.rb" with:
+ """ruby
+ describe "stubbing FOO" do
+ it "can stub undefined constant FOO" do
+ stub_const("FOO", 5)
+ FOO.should eq(5)
+ end
+
+ it "undefines the constant when the example completes" do
+ expect { FOO }.to raise_error(NameError)
+ end
+ end
+ """
+ When I run `rspec stub_const_spec.rb`
+ Then the examples should all pass
+
+ Scenario: Stub nested constant
+ Given a file named "stub_const_spec.rb" with:
+ """ruby
+ module MyGem
+ class SomeClass
+ end
+ end
+
+ module MyGem
+ describe SomeClass do
+ it "can stub an arbitrarily deep constant that is undefined" do
+ defined?(SomeClass::A).should be_false
+ stub_const("MyGem::SomeClass::A::B::C", 3)
+ SomeClass::A::B::C.should eq(3)
+ SomeClass::A.should be_a(Module)
+ end
+
+ it 'undefines the intermediary constants that were dynamically created' do
+ defined?(SomeClass).should be_true
+ defined?(SomeClass::A).should be_false
+ end
+ end
+ end
+ """
+ When I run `rspec stub_const_spec.rb`
+ Then the examples should all pass
Please sign in to comment.
Something went wrong with that request. Please try again.