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,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::EnsuresAllInteractionsSatisfied do
4
+ let(:ensures_all_interactions_satisfied) { isolate(Bogus::EnsuresAllInteractionsSatisfied) }
5
+
6
+ it "does nothing with all interactions satisfied" do
7
+ objects = 3.times.map { |n| Samples::FooFake.new }
8
+
9
+ expect {
10
+ ensures_all_interactions_satisfied.ensure_satisfied!(objects)
11
+ }.not_to raise_error
12
+ end
13
+
14
+ it "raises an error enumerating satisfied and unsatisfied interactions" do
15
+ foo = Samples::FooFake.new
16
+ foo.__shadow__.mocks(:foo, "a", "b") { "result" }
17
+ foo.__shadow__.mocks(:foo, "a", "c") { "result 2" }
18
+ foo.__shadow__.run(:foo, "a", "b")
19
+
20
+ bar = Samples::FooFake.new
21
+ bar.__shadow__.stubs(:foo, "a", "b") { "result" }
22
+ bar.__shadow__.stubs(:foo, "a", "c") { "result 2" }
23
+ bar.__shadow__.run(:foo, "a", "b")
24
+ bar.__shadow__.run(:foo, "x", "y")
25
+
26
+ msg = <<-EOF
27
+ Some of the mocked interactions were not satisfied:
28
+
29
+ - #{foo.inspect}.foo("a", "c")
30
+
31
+ The following calls were recorded:
32
+
33
+ - #{foo.inspect}.foo("a", "b")
34
+ - #{bar.inspect}.foo("a", "b")
35
+ - #{bar.inspect}.foo("x", "y")
36
+ EOF
37
+
38
+ expect {
39
+ ensures_all_interactions_satisfied.ensure_satisfied!([foo, bar])
40
+ }.to raise_error(Bogus::NotAllExpectationsSatisfied, msg.gsub(/ {4}/, ''))
41
+ end
42
+
43
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::FakeConfiguration do
4
+ let(:config) { Bogus::FakeConfiguration.new }
5
+
6
+ it "does not contain not configured fakes" do
7
+ config.include?(:foo).should be_false
8
+ end
9
+
10
+ def class_block(name)
11
+ config.get(name).class_block
12
+ end
13
+
14
+ def opts(name)
15
+ config.get(name).opts
16
+ end
17
+
18
+ def stubs(name)
19
+ config.get(name).stubs
20
+ end
21
+
22
+ it "contains configured fakes" do
23
+ config.evaluate do
24
+ fake(:foo, as: :class, class: proc{Samples::Foo}) do
25
+ bar "the bar"
26
+ end
27
+ end
28
+
29
+ config.include?(:foo).should be_true
30
+ config.include?(:bar).should be_false
31
+ end
32
+
33
+ it "returns the configuration for a fake" do
34
+ config.evaluate do
35
+ fake(:foo, as: :class, class: proc{Samples::Foo}) do
36
+ bar "the bar"
37
+ end
38
+ end
39
+
40
+ opts(:foo).should == {as: :class}
41
+ stubs(:foo).should == {bar: "the bar"}
42
+ class_block(:foo).call.should == Samples::Foo
43
+ end
44
+
45
+ context "with no class" do
46
+ it "does not return any class block" do
47
+ config.evaluate do
48
+ fake(:foo, as: :class) { bar "bar" }
49
+ end
50
+
51
+ opts(:foo).should == {as: :class}
52
+ stubs(:foo).should == {bar: "bar"}
53
+ class_block(:foo).should be_nil
54
+ end
55
+ end
56
+
57
+ context "with no options" do
58
+ it "does not return any options" do
59
+ config.evaluate do
60
+ fake(:foo) { bar "bar" }
61
+ end
62
+
63
+ opts(:foo).should == {}
64
+ stubs(:foo).should == {bar: "bar"}
65
+ class_block(:foo).should be_nil
66
+ end
67
+ end
68
+
69
+ context "with block return value definitions" do
70
+ it "returns the values, not blocks" do
71
+ config.evaluate do
72
+ fake(:foo) { bar {"bar"} }
73
+ end
74
+
75
+ stubs(:foo)[:bar].call.should == "bar"
76
+ end
77
+
78
+ it "does not evaluate the blocks when getting, nor when setting" do
79
+ config.evaluate do
80
+ fake(:foo) { bar { raise "gotcha" } }
81
+ end
82
+
83
+ block = stubs(:foo)[:bar]
84
+ expect{ block.call }.to raise_error
85
+ end
86
+ end
87
+
88
+ context "witn no stubs block" do
89
+ it "returns the options" do
90
+ config.evaluate do
91
+ fake(:foo, as: :class)
92
+ end
93
+
94
+ opts(:foo).should == {as: :class}
95
+ stubs(:foo).should == {}
96
+ class_block(:foo).should be_nil
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::FakesClasses do
4
+ let(:creates_fakes_with_stubbed_methods) { FakeCreatorOfFakes.new }
5
+ let(:overwrites_classes) { stub }
6
+ let(:overwritten_classes) { stub }
7
+
8
+ let(:fakes_classes) { isolate(Bogus::FakesClasses) }
9
+
10
+ module Samples
11
+ class WillBeOverwritten
12
+ end
13
+ end
14
+
15
+ before do
16
+ stub(overwrites_classes).overwrite
17
+ stub(overwritten_classes).add
18
+ end
19
+
20
+ it "creates a fake named after the class" do
21
+ fakes_classes.fake(Samples::WillBeOverwritten, foo: "bar")
22
+
23
+ creates_fakes_with_stubbed_methods.should have_created(:will_be_overwritten,
24
+ {as: :class, foo: "bar"}, Samples::WillBeOverwritten)
25
+ end
26
+
27
+ it "overwrites the class with the fake" do
28
+ fake = [:will_be_overwritten, {as: :class}, Samples::WillBeOverwritten]
29
+
30
+ fakes_classes.fake(Samples::WillBeOverwritten)
31
+
32
+ overwrites_classes.should have_received.overwrite("Samples::WillBeOverwritten", fake)
33
+ end
34
+
35
+ it "stores the overwritten class so that it can be replaced back later" do
36
+ fakes_classes.fake(Samples::WillBeOverwritten)
37
+
38
+ overwritten_classes.should have_received.add("Samples::WillBeOverwritten", Samples::WillBeOverwritten)
39
+ end
40
+
41
+ it "uses the passed fake name if provided" do
42
+ fakes_classes.fake(Samples::WillBeOverwritten, fake_name: :foo_bar)
43
+
44
+ creates_fakes_with_stubbed_methods.should have_created(:foo_bar, {as: :class}, Samples::WillBeOverwritten)
45
+ end
46
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bogus::HaveReceivedMatcher do
4
+ let(:verifies_stub_definition) { stub(verify!: nil) }
5
+ let(:records_double_interactions) { stub(record: nil) }
6
+ let(:have_received_matcher) { isolate(Bogus::HaveReceivedMatcher) }
7
+ let(:have_received) { have_received_matcher.method_call }
8
+ let(:fake) { Samples::FooFake.new }
9
+
10
+ before do
11
+ fake.foo("a", "b")
12
+ end
13
+
14
+ it "matches when the spy has received the message" do
15
+ fake.should have_received.foo("a", "b")
16
+ end
17
+
18
+ it "does not match if the spy hasn't received the message" do
19
+ fake.should_not have_received.foo("a", "c")
20
+ end
21
+
22
+ it "verifies that the method call has the right signature" do
23
+ mock(verifies_stub_definition).verify!(fake, :foo, ["a", "b"])
24
+
25
+ have_received.foo("a", "b")
26
+
27
+ have_received_matcher.matches?(fake)
28
+ end
29
+
30
+ it "records the interaction so that it can be checked by contract tests" do
31
+ mock(records_double_interactions).record(fake, :foo, ["a", "b"])
32
+
33
+ have_received.foo("a", "b")
34
+
35
+ have_received_matcher.matches?(fake)
36
+ end
37
+
38
+ it "returns a readable error message for object with no shadow" do
39
+ have_received.upcase
40
+
41
+ have_received_matcher.matches?("foo").should be_false
42
+ have_received_matcher.failure_message_for_should.should == Bogus::HaveReceivedMatcher::NO_SHADOW
43
+ have_received_matcher.failure_message_for_should_not.should == Bogus::HaveReceivedMatcher::NO_SHADOW
44
+ end
45
+
46
+ it "returns a readable error message for fakes" do
47
+ have_received.foo("a", "c")
48
+
49
+ have_received_matcher.matches?(fake)
50
+
51
+ have_received_matcher.failure_message_for_should.should ==
52
+ %Q{Expected #{fake.inspect} to have received foo("a", "c"), but it didn't.\n\n}+
53
+ %Q{The recorded interactions were:\n} +
54
+ %Q{ - foo("a", "b")\n}
55
+ end
56
+ end
@@ -7,13 +7,24 @@ describe Bogus::Interaction do
7
7
  [[:foo, [:bar], "value"], [:foo, [:bar], "value"]],
8
8
  [[:foo, [:bar]], [:foo, [:bar], "value"]],
9
9
  [[:foo, [:bar], "value"], [:foo, [:bar]]],
10
- [[:foo, [:bar]], [:foo, [:bar]]]
10
+ [[:foo, [:bar]], [:foo, [:bar]]],
11
+ [[:foo, [Bogus::AnyArgs]], [:foo, [:bar]]],
12
+ [[:foo, [:bar]], [:foo, [Bogus::AnyArgs]]],
13
+ [[:foo, [Bogus::AnyArgs], "same value"], [:foo, [:bar], "same value"]],
14
+ [[:foo, [:bar], "same value"], [:foo, [Bogus::AnyArgs], "same value"]],
15
+ [[:foo, [:bar, Bogus::Anything]], [:foo, [:bar, :baz]]],
16
+ [[:foo, [:bar, :baz]], [:foo, [:bar, Bogus::Anything]]],
17
+ [[:foo, [:bar, Bogus::Anything]], [:foo, [Bogus::Anything, :baz]]]
11
18
  ]
12
19
 
13
20
  different = [
14
21
  [[:foo, [:bar], "value"], [:foo, [:bar], "value2"]],
15
22
  [[:foo, [:bar], "value"], [:baz, [:bar], "value"]],
16
23
  [[:foo, [:baz], "value"], [:foo, [:bar], "value"]],
24
+ [[:foo, [Bogus::AnyArgs]], [:bar, [:bar]]],
25
+ [[:foo, [:bar]], [:bar, [Bogus::AnyArgs]]],
26
+ [[:foo, [Bogus::AnyArgs], "some value"], [:foo, [:bar], "other value"]],
27
+ [[:foo, [:bar], "some value"], [:foo, [Bogus::AnyArgs], "other value"]],
17
28
  [[:foo, [:bar]], [:foo, [:baz]]],
18
29
  [[:baz, [:bar]], [:foo, [:bar]]]
19
30
  ]
@@ -46,22 +57,22 @@ describe Bogus::Interaction do
46
57
  end
47
58
 
48
59
  it "differs exceptions from empty return values" do
49
- first = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
50
- second = Bogus::Interaction.new(:foo, :bar) { nil }
60
+ first = Bogus::Interaction.new(:foo, [:bar]) { raise SomeError }
61
+ second = Bogus::Interaction.new(:foo, [:bar]) { nil }
51
62
 
52
63
  first.should_not == second
53
64
  end
54
65
 
55
66
  it "differs raised exceptions from ones just returned from the block" do
56
- first = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
57
- second = Bogus::Interaction.new(:foo, :bar) { SomeError }
67
+ first = Bogus::Interaction.new(:foo, [:bar]) { raise SomeError }
68
+ second = Bogus::Interaction.new(:foo, [:bar]) { SomeError }
58
69
 
59
70
  first.should_not == second
60
71
  end
61
72
 
62
73
  it "considers exceptions of the same type as equal" do
63
- first = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
64
- second = Bogus::Interaction.new(:foo, :bar) { raise SomeError }
74
+ first = Bogus::Interaction.new(:foo, [:bar]) { raise SomeError }
75
+ second = Bogus::Interaction.new(:foo, [:bar]) { raise SomeError }
65
76
 
66
77
  first.should == second
67
78
  end
@@ -47,4 +47,46 @@ describe Bogus::InteractionsRepository do
47
47
 
48
48
  interactions_repository.for_fake(:foo).should == [Bogus::Interaction.new(:bar, [1, 2])]
49
49
  end
50
+
51
+ it "ignores arguments if the recorded interaction was recorded with any_args" do
52
+ interactions_repository.record(:foo, :bar, Bogus::AnyArgs)
53
+
54
+ recorded?(:foo, :bar, 1).should be_true
55
+ end
56
+
57
+ it "ignores arguments if the checked interaction has any_args" do
58
+ interactions_repository.record(:foo, :bar, 1)
59
+
60
+ recorded?(:foo, :bar, Bogus::AnyArgs).should be_true
61
+ end
62
+
63
+ it "takes method name into account when matching interaction with wildcard arguments" do
64
+ interactions_repository.record(:foo, :baz, 1)
65
+
66
+ recorded?(:foo, :bar, Bogus::AnyArgs).should be_false
67
+ end
68
+
69
+ it "ignores arguments if the recorded interaction was recorded with wildcard argument" do
70
+ interactions_repository.record(:foo, :bar, 1, Bogus::Anything)
71
+
72
+ recorded?(:foo, :bar, 1, 2).should be_true
73
+ end
74
+
75
+ it "takes other arguments into account when matching interactions with wildcards" do
76
+ interactions_repository.record(:foo, :bar, 1, Bogus::Anything)
77
+
78
+ recorded?(:foo, :bar, 2, 1).should be_false
79
+ end
80
+
81
+ it "ignores arguments if the checked interaction has any_args" do
82
+ interactions_repository.record(:foo, :bar, 1, 2)
83
+
84
+ recorded?(:foo, :bar, 1, Bogus::Anything).should be_true
85
+ end
86
+
87
+ it "takes method name into account when matching interaction with wildcard arguments" do
88
+ interactions_repository.record(:foo, :baz, 1, 2)
89
+
90
+ recorded?(:foo, :bar, 1, Bogus::Anything).should be_false
91
+ end
50
92
  end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Bogus
4
+ describe MakesSubstituteMethods do
5
+ class SampleForCopyingMethods
6
+ def self.foo(name, value = "hello", *rest, &block)
7
+ "this is the method body"
8
+ end
9
+ end
10
+
11
+ let(:method_stringifier) { isolate(MethodStringifier) }
12
+ let(:makes_substitute_methods) { isolate(MakesSubstituteMethods) }
13
+
14
+ it "makes a copy of the method with its params and adds recording" do
15
+ copy = makes_substitute_methods.stringify(SampleForCopyingMethods.method(:foo))
16
+
17
+ copy.should == <<-EOF
18
+ def foo(name, value = {}, *rest, &block)
19
+ __record__(:foo, name, value, *rest, &block)
20
+ end
21
+ EOF
22
+ end
23
+ end
24
+ end
@@ -4,27 +4,64 @@ describe Bogus::MockingDSL do
4
4
  class ExampleFoo
5
5
  def foo(bar)
6
6
  end
7
+
8
+ def hello(greeting, name)
9
+ end
10
+
11
+ def self.bar(baz)
12
+ "Hello #{baz}"
13
+ end
7
14
  end
8
15
 
9
16
  class Stubber
10
17
  extend Bogus::MockingDSL
11
18
  end
12
19
 
20
+ before do
21
+ Bogus.send(:clear_expectations)
22
+ end
23
+
13
24
  describe "#stub" do
14
- it "allows stubbing the existing methods" do
15
- baz = ExampleFoo.new
25
+ let(:baz) { ExampleFoo.new }
16
26
 
27
+ it "allows stubbing the existing methods" do
17
28
  Stubber.stub(baz).foo("bar") { :return_value }
18
29
 
19
30
  baz.foo("bar").should == :return_value
20
31
  end
21
32
 
33
+ it "can stub method with any parameters" do
34
+ Stubber.stub(baz).foo(Stubber.any_args) { :default_value }
35
+ Stubber.stub(baz).foo("bar") { :foo_value }
36
+
37
+ baz.foo("a").should == :default_value
38
+ baz.foo("b").should == :default_value
39
+ baz.foo("bar").should == :foo_value
40
+ end
41
+
42
+ it "can stub method with some wildcard parameters" do
43
+ Stubber.stub(baz).hello(Stubber.any_args) { :default_value }
44
+ Stubber.stub(baz).hello("welcome", Stubber.anything) { :greeting_value }
45
+
46
+ baz.hello("hello", "adam").should == :default_value
47
+ baz.hello("welcome", "adam").should == :greeting_value
48
+ baz.hello("welcome", "rudy").should == :greeting_value
49
+ end
50
+
22
51
  it "does not allow stubbing non-existent methods" do
23
52
  baz = ExampleFoo.new
24
53
  expect do
25
54
  Stubber.stub(baz).does_not_exist("bar") { :return_value }
26
55
  end.to raise_error(NameError)
27
56
  end
57
+
58
+ it "unstubs methods after each test" do
59
+ Stubber.stub(ExampleFoo).bar("John") { "something else" }
60
+
61
+ Bogus.after_each_test
62
+
63
+ ExampleFoo.bar("John").should == "Hello John"
64
+ end
28
65
  end
29
66
 
30
67
  describe "#have_received" do
@@ -52,12 +89,42 @@ describe Bogus::MockingDSL do
52
89
 
53
90
  it "can be used with plain old Ruby objects" do
54
91
  object = ExampleFoo.new
55
- stub(object).foo
92
+ Stubber.stub(object).foo(Stubber.any_args)
56
93
 
57
94
  object.foo('test')
58
95
 
59
96
  object.should Stubber.have_received.foo("test")
60
97
  end
98
+
99
+ class ClassWithMatches
100
+ def matches?(something)
101
+ end
102
+ end
103
+
104
+ it "can be used with objects that have same methods as an RSpec expectation" do
105
+ fake = Bogus.fake_for(:class_with_matches)
106
+
107
+ fake.matches?("foo")
108
+
109
+ fake.should Bogus.have_received.matches?("foo")
110
+ end
111
+
112
+ class PassesSelfToCollaborator
113
+ def hello(example)
114
+ example.foo(self)
115
+ end
116
+ end
117
+
118
+ it "can be used with self references" do
119
+ Bogus.record_calls_for(:passes_self_to_collaborator)
120
+
121
+ fake = Bogus.fake_for(:example_foo)
122
+ object = PassesSelfToCollaborator.new
123
+
124
+ object.hello(fake)
125
+
126
+ fake.should Bogus.have_received.foo(object)
127
+ end
61
128
  end
62
129
 
63
130
  class Mocker
@@ -65,12 +132,49 @@ describe Bogus::MockingDSL do
65
132
  end
66
133
 
67
134
  describe "#mock" do
68
- it "allows mocking the existing methods" do
69
- baz = ExampleFoo.new
135
+ let(:object) { ExampleFoo.new }
136
+ let(:fake) { Bogus.fake_for(:example_foo) { ExampleFoo } }
70
137
 
71
- Mocker.mock(baz).foo("bar") { :return_value }
138
+ shared_examples_for "mocking dsl" do
139
+ before do
140
+ Mocker.mock(baz).foo("bar") { :return_value }
141
+ end
72
142
 
73
- baz.foo("bar").should == :return_value
143
+ it "allows mocking the existing methods" do
144
+ baz.foo("bar").should == :return_value
145
+ end
146
+
147
+ it "verifies that the methods mocked exist" do
148
+ expect {
149
+ Mocker.mock(baz).does_not_exist { "whatever" }
150
+ }.to raise_error(NameError)
151
+ end
152
+
153
+ it "raises errors when mocks were not called" do
154
+ expect {
155
+ Bogus.after_each_test
156
+ }.to raise_error(Bogus::NotAllExpectationsSatisfied)
157
+ end
158
+
159
+ it "clears the data between tests" do
160
+ Bogus.send(:clear_expectations)
161
+
162
+ expect {
163
+ Bogus.after_each_test
164
+ }.not_to raise_error(Bogus::NotAllExpectationsSatisfied)
165
+ end
166
+ end
167
+
168
+ context "with fakes" do
169
+ it_behaves_like "mocking dsl" do
170
+ let(:baz) { fake }
171
+ end
172
+ end
173
+
174
+ context "with regular objects" do
175
+ it_behaves_like "mocking dsl" do
176
+ let(:baz) { object }
177
+ end
74
178
  end
75
179
  end
76
180
 
@@ -113,4 +217,127 @@ describe Bogus::MockingDSL do
113
217
  greeter.baz.foo.should == "bar"
114
218
  end
115
219
  end
220
+
221
+ class SampleOfConfiguredFake
222
+ def self.foo(x)
223
+ end
224
+
225
+ def self.bar(x, y)
226
+ end
227
+
228
+ def self.baz
229
+ end
230
+ end
231
+
232
+ describe "globally configured fakes" do
233
+ before do
234
+ Bogus.fakes do
235
+ fake(:globally_configured_fake, as: :class, class: proc{SampleOfConfiguredFake}) do
236
+ foo "foo"
237
+ bar { "bar" }
238
+ baz { raise "oh noes!" }
239
+ end
240
+ end
241
+ end
242
+
243
+ it "returns configured fakes" do
244
+ the_fake = Stubber.fake(:globally_configured_fake)
245
+
246
+ the_fake.foo('a').should == "foo"
247
+ the_fake.bar('a', 'b').should == "bar"
248
+ end
249
+
250
+ it "allows overwriting stubbed methods" do
251
+ the_fake = Stubber.fake(:globally_configured_fake, bar: "baz")
252
+
253
+ the_fake.foo('a').should == "foo"
254
+ the_fake.bar('a', 'b').should == "baz"
255
+ end
256
+
257
+ it "evaluates the block passed to method in configuration when method is called" do
258
+ the_fake = Stubber.fake(:globally_configured_fake)
259
+
260
+ expect{ the_fake.baz }.to raise_error("oh noes!")
261
+ end
262
+ end
263
+
264
+ describe "faking classes" do
265
+ class ThisClassWillBeReplaced
266
+ def self.hello(name)
267
+ "Hello, #{name}"
268
+ end
269
+ end
270
+ TheOriginalClass = ThisClassWillBeReplaced
271
+
272
+ after do
273
+ Bogus.reset_overwritten_classes
274
+ end
275
+
276
+ it "replaces the class for the duration of the test" do
277
+ Stubber.fake_class(ThisClassWillBeReplaced, hello: "replaced!")
278
+
279
+ ThisClassWillBeReplaced.hello("foo").should == "replaced!"
280
+ ThisClassWillBeReplaced.should_not equal(TheOriginalClass)
281
+ end
282
+
283
+ it "makes it possible to spy on classes" do
284
+ Stubber.fake_class(ThisClassWillBeReplaced)
285
+
286
+ ThisClassWillBeReplaced.hello("foo")
287
+
288
+ ThisClassWillBeReplaced.should Bogus.have_received.hello("foo")
289
+ ThisClassWillBeReplaced.should_not Bogus.have_received.hello("bar")
290
+ end
291
+
292
+ it "restores the class after the test has finished" do
293
+ Stubber.fake_class(ThisClassWillBeReplaced)
294
+ Bogus.reset_overwritten_classes
295
+
296
+ ThisClassWillBeReplaced.should equal(TheOriginalClass)
297
+ end
298
+ end
299
+
300
+ class SampleForContracts
301
+ def initialize(name)
302
+ @name = name
303
+ end
304
+
305
+ def greet(greeting = "Hello")
306
+ "#{greeting}, #{@name}!"
307
+ end
308
+ end
309
+
310
+ describe "contracts" do
311
+ let(:sample) { SampleForContracts.new("John") }
312
+
313
+ before do
314
+ Bogus.reset!
315
+
316
+ Stubber.fake(:sample_for_contracts, greet: "Welcome, John!")
317
+
318
+ Bogus.after_each_test
319
+
320
+ Bogus.record_calls_for(:sample_for_contracts)
321
+ end
322
+
323
+ it "passes when all the mocked interactions were executed" do
324
+ sample.greet("Welcome").should == "Welcome, John!"
325
+
326
+ Bogus.after_each_test
327
+
328
+ expect {
329
+ Bogus.verify_contract!(:sample_for_contracts)
330
+ }.not_to raise_error
331
+ end
332
+
333
+ it "fails when contracts are fullfilled" do
334
+ sample.greet("Hello").should == "Hello, John!"
335
+
336
+ Bogus.after_each_test
337
+
338
+ expect {
339
+ Bogus.verify_contract!(:sample_for_contracts)
340
+ }.to raise_error(Bogus::ContractNotFulfilled)
341
+ end
342
+ end
116
343
  end