bogus 0.0.2 → 0.0.3.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile.lock +14 -2
  3. data/Guardfile +5 -0
  4. data/README.md +7 -249
  5. data/bogus.gemspec +3 -1
  6. data/features/.nav +21 -0
  7. data/features/authors.md +42 -0
  8. data/{CHANGELOG.md → features/changelog.md} +9 -2
  9. data/features/configuration_options.feature +1 -2
  10. data/features/{contract_tests_mocks.feature → contract_tests/contract_tests_mocks.feature} +4 -1
  11. data/features/{contract_tests_spies.feature → contract_tests/contract_tests_spies.feature} +2 -0
  12. data/features/{contract_tests_stubs.feature → contract_tests/contract_tests_stubs.feature} +14 -0
  13. data/features/contract_tests/readme.md +26 -0
  14. data/features/{return_value_contracts.feature → contract_tests/return_value_contracts.feature} +6 -2
  15. data/features/{anonymous_doubles.feature → fakes/anonymous_doubles.feature} +24 -8
  16. data/features/{fake_objects.feature → fakes/fake_objects.feature} +39 -4
  17. data/features/fakes/global_fake_configuration.feature +88 -0
  18. data/features/fakes/readme.md +11 -0
  19. data/features/fakes/replacing_classes.feature +148 -0
  20. data/features/getting_started.md +36 -0
  21. data/features/license.md +9 -0
  22. data/features/readme.md +173 -0
  23. data/features/safe_stubbing/argument_matchers.feature +30 -0
  24. data/features/safe_stubbing/readme.md +35 -0
  25. data/features/{safe_mocking.feature → safe_stubbing/safe_mocking.feature} +14 -0
  26. data/features/{safe_stubbing.feature → safe_stubbing/safe_stubbing.feature} +18 -4
  27. data/features/{spies.feature → safe_stubbing/spies.feature} +19 -4
  28. data/features/step_definitions/rspec_steps.rb +14 -5
  29. data/features/support/env.rb +4 -0
  30. data/lib/bogus.rb +2 -0
  31. data/lib/bogus/adds_recording.rb +11 -7
  32. data/lib/bogus/any_args.rb +7 -0
  33. data/lib/bogus/anything.rb +11 -0
  34. data/lib/bogus/contract_not_fulfilled.rb +17 -10
  35. data/lib/bogus/copies_classes.rb +2 -6
  36. data/lib/bogus/creates_fakes_with_stubbed_methods.rb +40 -0
  37. data/lib/bogus/double.rb +28 -8
  38. data/lib/bogus/ensures_all_interactions_satisfied.rb +36 -0
  39. data/lib/bogus/fake.rb +6 -0
  40. data/lib/bogus/fake_configuration.rb +69 -0
  41. data/lib/bogus/fakes_classes.rb +21 -0
  42. data/lib/bogus/has_overwritten_methods.rb +24 -0
  43. data/lib/bogus/have_received_matcher.rb +63 -0
  44. data/lib/bogus/injector.rb +36 -14
  45. data/lib/bogus/interaction.rb +33 -17
  46. data/lib/bogus/makes_substitute_methods.rb +15 -0
  47. data/lib/bogus/mocking_dsl.rb +31 -0
  48. data/lib/bogus/multi_stubber.rb +15 -0
  49. data/lib/bogus/not_all_expectations_satisfied.rb +27 -0
  50. data/lib/bogus/overwriten_classes.rb +15 -0
  51. data/lib/bogus/overwrites_classes.rb +2 -2
  52. data/lib/bogus/overwrites_methods.rb +42 -0
  53. data/lib/bogus/proxies_method_calls.rb +23 -0
  54. data/lib/bogus/proxy_class.rb +25 -16
  55. data/lib/bogus/public_methods.rb +36 -11
  56. data/lib/bogus/record_interactions.rb +3 -9
  57. data/lib/bogus/recording_proxy.rb +5 -0
  58. data/lib/bogus/registers_created_fakes.rb +2 -1
  59. data/lib/bogus/resets_overwritten_classes.rb +14 -0
  60. data/lib/bogus/resets_stubbed_methods.rb +12 -0
  61. data/lib/bogus/responds_to_everything.rb +11 -0
  62. data/lib/bogus/rspec.rb +7 -0
  63. data/lib/bogus/rspec_adapter.rb +17 -0
  64. data/lib/bogus/rspec_extensions.rb +8 -20
  65. data/lib/bogus/shadow.rb +60 -0
  66. data/lib/bogus/verifies_contracts.rb +5 -1
  67. data/lib/bogus/verifies_stub_definition.rb +5 -0
  68. data/lib/bogus/version.rb +1 -1
  69. data/lib/tracks_existence_of_test_doubles.rb +11 -0
  70. data/spec/bogus/adds_recording_spec.rb +46 -10
  71. data/spec/bogus/anything_spec.rb +13 -0
  72. data/spec/bogus/copies_classes_spec.rb +4 -3
  73. data/spec/bogus/creates_fakes_with_stubbed_methods_spec.rb +121 -0
  74. data/spec/bogus/double_spec.rb +63 -20
  75. data/spec/bogus/ensures_all_interactions_satisfied_spec.rb +43 -0
  76. data/spec/bogus/fake_configuration_spec.rb +99 -0
  77. data/spec/bogus/fakes_classes_spec.rb +46 -0
  78. data/spec/bogus/have_received_matcher_spec.rb +56 -0
  79. data/spec/bogus/interaction_spec.rb +18 -7
  80. data/spec/bogus/interactions_repository_spec.rb +42 -0
  81. data/spec/bogus/makes_substitute_methods_spec.rb +24 -0
  82. data/spec/bogus/mocking_dsl_spec.rb +234 -7
  83. data/spec/bogus/multi_stubber_spec.rb +31 -0
  84. data/spec/bogus/overwriten_classes_spec.rb +27 -0
  85. data/spec/bogus/overwrites_classes_spec.rb +2 -2
  86. data/spec/bogus/overwrites_methods_spec.rb +107 -0
  87. data/spec/bogus/proxy_class_spec.rb +6 -0
  88. data/spec/bogus/record_interactions_spec.rb +3 -4
  89. data/spec/bogus/registers_created_fakes_spec.rb +8 -0
  90. data/spec/bogus/resets_overwritten_classes_spec.rb +26 -0
  91. data/spec/bogus/resets_stubbed_methods_spec.rb +16 -0
  92. data/spec/bogus/shadow_spec.rb +182 -0
  93. data/spec/bogus/verifies_contracts_spec.rb +9 -3
  94. data/spec/bogus/verifies_stub_definition_spec.rb +4 -0
  95. data/spec/spec_helper.rb +3 -0
  96. data/spec/support/fake_creator_of_fakes.rb +15 -0
  97. data/spec/support/sample_fake.rb +13 -0
  98. data/spec/tracks_existence_of_test_doubles_spec.rb +26 -0
  99. metadata +105 -32
  100. data/lib/bogus/creates_anonymous_stubs.rb +0 -27
  101. data/lib/bogus/invocation_matcher.rb +0 -27
  102. data/lib/bogus/rr_proxy.rb +0 -5
  103. data/spec/bogus/invocation_matcher_spec.rb +0 -26
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::MultiStubber do
4
+ let(:double) { FakeDouble.new }
5
+ let(:create_double) { proc{ double } }
6
+ let(:any_args) { Bogus::AnyArgs }
7
+
8
+ let(:multi_stubber) { isolate(Bogus::MultiStubber) }
9
+
10
+ it "stubs all the given methods with any args returning the given value" do
11
+ multi_stubber.stub_all(Object.new, foo: 1, bar: 2)
12
+
13
+ double.stubbed.should == [[:foo, [any_args], 1], [:bar, [any_args], 2]]
14
+ end
15
+
16
+ it "uses passed procs as the return value block" do
17
+ multi_stubber.stub_all(Object.new, foo: proc{ 1 })
18
+
19
+ double.stubbed.should == [[:foo, [any_args], 1]]
20
+ end
21
+
22
+ class FakeDouble
23
+ def stubbed
24
+ @stubbed ||= []
25
+ end
26
+
27
+ def stubs(name, *args, &return_value)
28
+ stubbed << [name, args, return_value.call]
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::OverwrittenClasses do
4
+ let(:overwritten_classes) { Bogus::OverwrittenClasses.new }
5
+
6
+ let(:klass) { Class.new }
7
+
8
+ it "adds classes" do
9
+ overwritten_classes.add("Foo::Bar", klass)
10
+ overwritten_classes.add("Baz::Bam", klass)
11
+
12
+ overwritten_classes.classes.should == [["Foo::Bar", klass],
13
+ ["Baz::Bam", klass]]
14
+ end
15
+
16
+ it "clears overwritten classes" do
17
+ overwritten_classes.add("Foo::Bar", klass)
18
+ overwritten_classes.add("Baz::Bam", klass)
19
+ overwritten_classes.clear
20
+
21
+ overwritten_classes.classes.should == []
22
+ end
23
+
24
+ it "returns an empty array with no classes" do
25
+ overwritten_classes.classes.should == []
26
+ end
27
+ end
@@ -12,13 +12,13 @@ describe Bogus::OverwritesClasses do
12
12
  let(:overwrites_classes) { Bogus::OverwritesClasses.new }
13
13
 
14
14
  it "overwrites nested classes" do
15
- overwrites_classes.overwrite(SampleOuterModule::SampleModule::SampleClass, new_class)
15
+ overwrites_classes.overwrite('SampleOuterModule::SampleModule::SampleClass', new_class)
16
16
 
17
17
  SampleOuterModule::SampleModule::SampleClass.should equal(new_class)
18
18
  end
19
19
 
20
20
  it "overwrites top level classes" do
21
- overwrites_classes.overwrite(SampleOuterModule, new_class)
21
+ overwrites_classes.overwrite('SampleOuterModule', new_class)
22
22
 
23
23
  SampleOuterModule.should equal(new_class)
24
24
  end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ module Bogus
4
+ describe OverwritesMethods do
5
+ let(:method_stringifier) { MethodStringifier.new }
6
+ let(:makes_substitute_methods) { isolate(MakesSubstituteMethods) }
7
+ let(:overwriter) { isolate(OverwritesMethods) }
8
+
9
+ let(:object) { SampleOfOverwriting.new }
10
+
11
+ context "with regular objects" do
12
+ class SampleOfOverwriting
13
+ def greet(name)
14
+ "Hello #{name}"
15
+ end
16
+
17
+ def wave(part_of_body = "hand", speed = "slowly")
18
+ "I'm waving my #{part_of_body} #{speed}"
19
+ end
20
+ end
21
+
22
+ before do
23
+ overwriter.overwrite(object, :greet)
24
+ end
25
+
26
+ it "does not change the method signature" do
27
+ object.greet("John").should == object
28
+ end
29
+
30
+ it "does not change the method signature" do
31
+ expect {
32
+ object.greet("John", "Paul")
33
+ }.to raise_error(ArgumentError)
34
+ end
35
+
36
+ it "adds interaction recording to the overwritten object" do
37
+ object.greet("John")
38
+
39
+ object.should Bogus.have_received.greet("John")
40
+ object.should_not Bogus.have_received.greet("Paul")
41
+ end
42
+
43
+ it "can reset the overwritten methods" do
44
+ overwriter.reset(object)
45
+
46
+ object.greet("John").should == "Hello John"
47
+ end
48
+
49
+ it "is imdepotent when overwriting" do
50
+ overwriter.overwrite(object, :greet)
51
+ overwriter.overwrite(object, :greet)
52
+ overwriter.overwrite(object, :greet)
53
+
54
+ overwriter.reset(object)
55
+
56
+ object.greet("John").should == "Hello John"
57
+ end
58
+ end
59
+
60
+ context "with objects that use method missing" do
61
+ class UsesMethodMissing
62
+ def respond_to?(name)
63
+ name == :greet
64
+ end
65
+
66
+ def method_missing(name, *args, &block)
67
+ "the original return value"
68
+ end
69
+ end
70
+
71
+ let(:object) { UsesMethodMissing.new }
72
+
73
+ before do
74
+ overwriter.overwrite(object, :greet)
75
+ end
76
+
77
+ it "can overwrite the non-existent methods" do
78
+ object.greet.should equal(object)
79
+ end
80
+
81
+ it "can be reset back to the original state" do
82
+ overwriter.overwrite(object, :greet)
83
+ overwriter.overwrite(object, :greet)
84
+
85
+ overwriter.reset(object)
86
+
87
+ object.greet.should == "the original return value"
88
+ end
89
+ end
90
+
91
+ context "with fakes" do
92
+ let(:fake) { Samples::FooFake.new }
93
+
94
+ it "does nothing because fakes methods already work as we need" do
95
+ overwriter.overwrite(fake, :foo_bar)
96
+
97
+ fake.should_not respond_to(:foo_bar)
98
+ end
99
+
100
+ it "does not reset fakes, because there is nothing to reset" do
101
+ expect {
102
+ overwriter.reset(fake)
103
+ }.not_to raise_error
104
+ end
105
+ end
106
+ end
107
+ end
@@ -3,6 +3,8 @@ require 'spec_helper'
3
3
  describe Bogus::ProxyClass do
4
4
  module SampleModule
5
5
  class GrandLibrary
6
+ SAMPLE_CONSTANT = "foo"
7
+
6
8
  def checkout(book, user)
7
9
  :checkouted
8
10
  end
@@ -69,6 +71,10 @@ describe Bogus::ProxyClass do
69
71
  }.to raise_error(StandardError)
70
72
  end
71
73
 
74
+ it "allows accessing the constants defined on proxied class" do
75
+ proxy_class::SAMPLE_CONSTANT.should == "foo"
76
+ end
77
+
72
78
  class FakeRepository
73
79
  def initialize
74
80
  @recordings = []
@@ -7,21 +7,20 @@ describe Bogus::RecordInteractions do
7
7
  end
8
8
 
9
9
  let(:sample) { SampleRecordsInteractions.new }
10
- let!(:rr) { Bogus::RRProxy }
11
10
 
12
11
  it "allows verifying that interactions happened" do
13
12
  sample.__record__(:foo, 1, 2, 3)
14
13
 
15
- sample.__inner_object__.should have_received.foo(1, 2, 3)
14
+ sample.__shadow__.has_received(:foo, [1,2,3]).should be_true
16
15
  end
17
16
 
18
17
  it "allows verifying that interactions didn't happen" do
19
18
  sample.__record__(:bar)
20
19
 
21
- sample.__inner_object__.should_not have_received.foo
20
+ sample.__shadow__.has_received(:foo, [1,2,3]).should be_false
22
21
  end
23
22
 
24
- it "returns self from record" do
23
+ it "returns self from record by default" do
25
24
  sample.__record__(:foo).should == sample
26
25
  end
27
26
  end
@@ -3,12 +3,14 @@ require 'spec_helper'
3
3
  describe Bogus::RegistersCreatedFakes do
4
4
  let(:fake_registry) { stub }
5
5
  let(:creates_fakes) { stub }
6
+ let(:double_tracker) { stub }
6
7
 
7
8
  let(:registers_created_fakes) { isolate(Bogus::RegistersCreatedFakes) }
8
9
 
9
10
  before do
10
11
  stub(fake_registry).store
11
12
  stub(creates_fakes).create { :the_fake }
13
+ stub(double_tracker).track(:the_fake)
12
14
  end
13
15
 
14
16
  it "registers the fakes created by creates_fakes" do
@@ -17,6 +19,12 @@ describe Bogus::RegistersCreatedFakes do
17
19
  fake_registry.should have_received.store(:foo, :the_fake)
18
20
  end
19
21
 
22
+ it "tracks the created fakes for purposes of mock expectations" do
23
+ registers_created_fakes.create(:foo, as: :instance) { Object }
24
+
25
+ double_tracker.should have_received.track(:the_fake)
26
+ end
27
+
20
28
  it "returns the created fake" do
21
29
  fake = registers_created_fakes.create(:foo, as: :instance) { Object }
22
30
 
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::ResetsOverwrittenClasses do
4
+ let(:classes) { [['Foo', :foo], ['Bar', :bar]] }
5
+ let(:overwritten_classes) { stub }
6
+ let(:overwrites_classes) { stub }
7
+
8
+ let(:resets_overwritten_classes) { isolate(Bogus::ResetsOverwrittenClasses) }
9
+
10
+ before do
11
+ stub(overwritten_classes).classes { classes }
12
+ stub(overwritten_classes).clear
13
+ stub(overwrites_classes).overwrite
14
+
15
+ resets_overwritten_classes.reset
16
+ end
17
+
18
+ it "overwrites back all of the overwritten classes" do
19
+ overwrites_classes.should have_received.overwrite('Foo', :foo)
20
+ overwrites_classes.should have_received.overwrite('Bar', :bar)
21
+ end
22
+
23
+ it "clears the overwritten classes" do
24
+ overwritten_classes.should have_received.clear
25
+ end
26
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::ResetsStubbedMethods do
4
+ let(:double_tracker) { stub }
5
+ let(:overwrites_methods) { stub }
6
+
7
+ let(:resets_stubbed_methods) { isolate(Bogus::ResetsStubbedMethods) }
8
+
9
+ it "resets all stubbed objects back to previous implementation" do
10
+ foo = stub
11
+ stub(double_tracker).doubles { [foo] }
12
+ mock(overwrites_methods).reset(foo)
13
+
14
+ resets_stubbed_methods.reset_all_doubles
15
+ end
16
+ end
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::Shadow do
4
+ let(:object) { Samples::FooFake.new }
5
+ let(:shadow) { Bogus::Shadow.new{ object } }
6
+
7
+ shared_examples_for "spying on shadows" do
8
+ context "spying" do
9
+ before do
10
+ shadow.run(:foo, "a", "b") rescue nil # for when the method raises an error
11
+ end
12
+
13
+ it "returns the called methods" do
14
+ shadow.has_received(:foo, ["a", "b"]).should be_true
15
+ end
16
+
17
+ it "does not return true for interactions that did not happen" do
18
+ shadow.has_received(:foo, ["a", "c"]).should be_false
19
+ shadow.has_received(:bar, ["a", "c"]).should be_false
20
+ end
21
+ end
22
+ end
23
+
24
+ context "unrecorded interactions" do
25
+ it "returns the object, so that calls can be chained" do
26
+ shadow.run(:foo, "a", "b").should == object
27
+ end
28
+
29
+ include_examples "spying on shadows"
30
+ end
31
+
32
+ context "interactions that raise exceptions" do
33
+ class SomeWeirdException < StandardError; end
34
+
35
+ before do
36
+ shadow.stubs(:foo, "a", "b") { raise SomeWeirdException, "failed!" }
37
+ end
38
+
39
+ it "raises the error when called" do
40
+ expect {
41
+ shadow.run(:foo, "a", "b")
42
+ }.to raise_error(SomeWeirdException, "failed!")
43
+ end
44
+
45
+ include_examples "spying on shadows"
46
+ end
47
+
48
+ context "interactions with no return value" do
49
+ before do
50
+ shadow.stubs(:foo, ["a", "b"])
51
+ end
52
+
53
+ it "returns the object" do
54
+ shadow.run(:foo, ["a", "b"]).should == object
55
+ end
56
+
57
+ include_examples "spying on shadows"
58
+ end
59
+
60
+ context "interactions with AnyArgs" do
61
+ before do
62
+ shadow.stubs(:foo, "a", "b") { "old specific value" }
63
+ shadow.stubs(:foo, Bogus::AnyArgs) { "default value" }
64
+ shadow.stubs(:foo, "a", "d") { "new specific value" }
65
+ end
66
+
67
+ it "changes the default value returned from method" do
68
+ shadow.run(:foo, "b", "c").should == "default value"
69
+ end
70
+
71
+ it "overwrites the old specific stubbed values" do
72
+ shadow.run(:foo, "a", "b").should == "default value"
73
+ end
74
+
75
+ it "does not affect the new specific stubbed values" do
76
+ shadow.run(:foo, "a", "d").should == "new specific value"
77
+ end
78
+
79
+ it "allows spying on calls using any args" do
80
+ shadow.run(:foo, "a", "c")
81
+
82
+ shadow.has_received(:foo, [Bogus::AnyArgs]).should be_true
83
+ end
84
+ end
85
+
86
+ context "interactions that take anything" do
87
+ before do
88
+ shadow.stubs(:foo, "a", Bogus::Anything) { "return value" }
89
+ end
90
+
91
+ it "changes the return value for calls that match" do
92
+ shadow.run(:foo, "a", "c").should == "return value"
93
+ end
94
+
95
+ it "does not affect the return value for other calls" do
96
+ shadow.stubs(:foo, "a", "b") { "specific value" }
97
+
98
+ shadow.run(:foo, "a", "b").should == "specific value"
99
+ end
100
+
101
+ it "allows spying on calls using anything in args" do
102
+ shadow.run(:foo, "a", "b")
103
+
104
+ shadow.has_received(:foo, [Bogus::Anything, "b"]).should be_true
105
+ end
106
+ end
107
+
108
+ context "stubbed interactions" do
109
+ before do
110
+ shadow.stubs(:foo, "a", "b") { "stubbed value" }
111
+ end
112
+
113
+ it "returns the stubbed value" do
114
+ shadow.run(:foo, "a", "b").should == "stubbed value"
115
+ end
116
+
117
+ it "returns the latest stubbed value" do
118
+ shadow.stubs(:foo, "a", "b") { "stubbed twice" }
119
+ shadow.stubs(:foo, "b", "c") { "different params" }
120
+
121
+ shadow.run(:foo, "a", "b").should == "stubbed twice"
122
+ shadow.run(:foo, "b", "c").should == "different params"
123
+ end
124
+
125
+ it "returns the default value for non-stubbed calls" do
126
+ shadow.run(:foo, "c", "d").should == object
127
+ shadow.run(:bar).should == object
128
+ end
129
+
130
+ it "does not contribute towards unsatisfied interactions" do
131
+ shadow.unsatisfied_interactions.should be_empty
132
+ end
133
+
134
+ it "adds required interaction when mocking over stubbing" do
135
+ shadow.mocks(:foo, "a", "b") { "stubbed value" }
136
+
137
+ shadow.unsatisfied_interactions.should_not be_empty
138
+ end
139
+
140
+ include_examples "spying on shadows"
141
+ end
142
+
143
+ context "mocked interactions" do
144
+ before do
145
+ shadow.mocks(:foo, "a", "b") { "mocked value" }
146
+ end
147
+
148
+ it "returns the mocked value" do
149
+ shadow.run(:foo, "a", "b").should == "mocked value"
150
+ end
151
+
152
+ it "overwrites the stubbed value" do
153
+ shadow.stubs(:foo, "a", "c") { "stubbed value" }
154
+ shadow.mocks(:foo, "a", "c") { "mocked value" }
155
+
156
+ shadow.run(:foo, "a", "c").should == "mocked value"
157
+ end
158
+
159
+ it "is overwritten by stubbing" do
160
+ shadow.mocks(:foo, "a", "c") { "mocked value" }
161
+ shadow.stubs(:foo, "a", "c") { "stubbed value" }
162
+
163
+ shadow.run(:foo, "a", "c").should == "stubbed value"
164
+ end
165
+
166
+ it "removes the required interaction when stubbing over mocking" do
167
+ shadow.stubs(:foo, "a", "b") { "stubbed value" }
168
+
169
+ shadow.unsatisfied_interactions.should be_empty
170
+ end
171
+
172
+ it "returns the default value for non-stubbed calls" do
173
+ shadow.run(:foo, "a", "c").should == object
174
+ end
175
+
176
+ it "contributes towards unsatisfied interactions" do
177
+ shadow.unsatisfied_interactions.should =~ [Bogus::Interaction.new(:foo, ["a", "b"])]
178
+ end
179
+
180
+ include_examples "spying on shadows"
181
+ end
182
+ end