changelog shortlog tags changeset manifest revisions annotate raw

vendor/plugins/rspec/lib/spec/mocks.rb

changeset 15: 64acf98d15f4
author: moriq@moriq.com
date: Mon Mar 10 10:12:58 2008 +0900 (16 years ago)
permissions: -rw-r--r--
description: add plugins rspec
1require 'spec/mocks/methods'
2require 'spec/mocks/argument_constraint_matchers'
3require 'spec/mocks/spec_methods'
4require 'spec/mocks/proxy'
5require 'spec/mocks/mock'
6require 'spec/mocks/argument_expectation'
7require 'spec/mocks/message_expectation'
8require 'spec/mocks/order_group'
9require 'spec/mocks/errors'
10require 'spec/mocks/error_generator'
11require 'spec/mocks/extensions/object'
12require 'spec/mocks/space'
13
14
15module Spec
16 # == Mocks and Stubs
17 #
18 # RSpec will create Mock Objects and Stubs for you at runtime, or attach stub/mock behaviour
19 # to any of your real objects (Partial Mock/Stub). Because the underlying implementation
20 # for mocks and stubs is the same, you can intermingle mock and stub
21 # behaviour in either dynamically generated mocks or your pre-existing classes.
22 # There is a semantic difference in how they are created, however,
23 # which can help clarify the role it is playing within a given spec.
24 #
25 # == Mock Objects
26 #
27 # Mocks are objects that allow you to set and verify expectations that they will
28 # receive specific messages during run time. They are very useful for specifying how the subject of
29 # the spec interacts with its collaborators. This approach is widely known as "interaction
30 # testing".
31 #
32 # Mocks are also very powerful as a design tool. As you are
33 # driving the implementation of a given class, Mocks provide an anonymous
34 # collaborator that can change in behaviour as quickly as you can write an expectation in your
35 # spec. This flexibility allows you to design the interface of a collaborator that often
36 # does not yet exist. As the shape of the class being specified becomes more clear, so do the
37 # requirements for its collaborators - often leading to the discovery of new types that are
38 # needed in your system.
39 #
40 # Read Endo-Testing[http://www.mockobjects.com/files/endotesting.pdf] for a much
41 # more in depth description of this process.
42 #
43 # == Stubs
44 #
45 # Stubs are objects that allow you to set "stub" responses to
46 # messages. As Martin Fowler points out on his site,
47 # mocks_arent_stubs[http://www.martinfowler.com/articles/mocksArentStubs.html].
48 # Paraphrasing Fowler's paraphrasing
49 # of Gerard Meszaros: Stubs provide canned responses to messages they might receive in a test, while
50 # mocks allow you to specify and, subsquently, verify that certain messages should be received during
51 # the execution of a test.
52 #
53 # == Partial Mocks/Stubs
54 #
55 # RSpec also supports partial mocking/stubbing, allowing you to add stub/mock behaviour
56 # to instances of your existing classes. This is generally
57 # something to be avoided, because changes to the class can have ripple effects on
58 # seemingly unrelated specs. When specs fail due to these ripple effects, the fact
59 # that some methods are being mocked can make it difficult to understand why a
60 # failure is occurring.
61 #
62 # That said, partials do allow you to expect and
63 # verify interactions with class methods such as +#find+ and +#create+
64 # on Ruby on Rails model classes.
65 #
66 # == Further Reading
67 #
68 # There are many different viewpoints about the meaning of mocks and stubs. If you are interested
69 # in learning more, here is some recommended reading:
70 #
71 # * Mock Objects: http://www.mockobjects.com/
72 # * Endo-Testing: http://www.mockobjects.com/files/endotesting.pdf
73 # * Mock Roles, Not Objects: http://www.mockobjects.com/files/mockrolesnotobjects.pdf
74 # * Test Double Patterns: http://xunitpatterns.com/Test%20Double%20Patterns.html
75 # * Mocks aren't stubs: http://www.martinfowler.com/articles/mocksArentStubs.html
76 #
77 # == Creating a Mock
78 #
79 # You can create a mock in any specification (or setup) using:
80 #
81 # mock(name, options={})
82 #
83 # The optional +options+ argument is a +Hash+. Currently the only supported
84 # option is +:null_object+. Setting this to true instructs the mock to ignore
85 # any messages it hasn’t been told to expect – and quietly return itself. For example:
86 #
87 # mock("person", :null_object => true)
88 #
89 # == Creating a Stub
90 #
91 # You can create a stub in any specification (or setup) using:
92 #
93 # stub(name, stub_methods_and_values_hash)
94 #
95 # For example, if you wanted to create an object that always returns
96 # "More?!?!?!" to "please_sir_may_i_have_some_more" you would do this:
97 #
98 # stub("Mr Sykes", :please_sir_may_i_have_some_more => "More?!?!?!")
99 #
100 # == Creating a Partial Mock
101 #
102 # You don't really "create" a partial mock, you simply add method stubs and/or
103 # mock expectations to existing classes and objects:
104 #
105 # Factory.should_receive(:find).with(id).and_return(value)
106 # obj.stub!(:to_i).and_return(3)
107 # etc ...
108 #
109 # == Expecting Messages
110 #
111 # my_mock.should_receive(:sym)
112 # my_mock.should_not_receive(:sym)
113 #
114 # == Expecting Arguments
115 #
116 # my_mock.should_receive(:sym).with(*args)
117 # my_mock.should_not_receive(:sym).with(*args)
118 #
119 # == Argument Constraints using Expression Matchers
120 #
121 # Arguments that are passed to #with are compared with actual arguments received
122 # using == by default. In cases in which you want to specify things about the arguments
123 # rather than the arguments themselves, you can use any of the Expression Matchers.
124 # They don't all make syntactic sense (they were primarily designed for use with
125 # Spec::Expectations), but you are free to create your own custom Spec::Matchers.
126 #
127 # Spec::Mocks does provide one additional Matcher method named #ducktype.
128 #
129 # In addition, Spec::Mocks adds some keyword Symbols that you can use to
130 # specify certain kinds of arguments:
131 #
132 # my_mock.should_receive(:sym).with(no_args())
133 # my_mock.should_receive(:sym).with(any_args())
134 # my_mock.should_receive(:sym).with(1, an_instance_of(Numeric), "b") #2nd argument can any type of Numeric
135 # my_mock.should_receive(:sym).with(1, boolean(), "b") #2nd argument can true or false
136 # my_mock.should_receive(:sym).with(1, /abc/, "b") #2nd argument can be any String matching the submitted Regexp
137 # my_mock.should_receive(:sym).with(1, anything(), "b") #2nd argument can be anything at all
138 # my_mock.should_receive(:sym).with(1, ducktype(:abs, :div), "b")
139 # #2nd argument can be object that responds to #abs and #div
140 #
141 # == Receive Counts
142 #
143 # my_mock.should_receive(:sym).once
144 # my_mock.should_receive(:sym).twice
145 # my_mock.should_receive(:sym).exactly(n).times
146 # my_mock.should_receive(:sym).at_least(:once)
147 # my_mock.should_receive(:sym).at_least(:twice)
148 # my_mock.should_receive(:sym).at_least(n).times
149 # my_mock.should_receive(:sym).at_most(:once)
150 # my_mock.should_receive(:sym).at_most(:twice)
151 # my_mock.should_receive(:sym).at_most(n).times
152 # my_mock.should_receive(:sym).any_number_of_times
153 #
154 # == Ordering
155 #
156 # my_mock.should_receive(:sym).ordered
157 # my_mock.should_receive(:other_sym).ordered
158 # #This will fail if the messages are received out of order
159 #
160 # == Setting Reponses
161 #
162 # Whether you are setting a mock expectation or a simple stub, you can tell the
163 # object precisely how to respond:
164 #
165 # my_mock.should_receive(:sym).and_return(value)
166 # my_mock.should_receive(:sym).exactly(3).times.and_return(value1, value2, value3)
167 # # returns value1 the first time, value2 the second, etc
168 # my_mock.should_receive(:sym).and_return { ... } #returns value returned by the block
169 # my_mock.should_receive(:sym).and_raise(error)
170 # #error can be an instantiated object or a class
171 # #if it is a class, it must be instantiable with no args
172 # my_mock.should_receive(:sym).and_throw(:sym)
173 # my_mock.should_receive(:sym).and_yield(values,to,yield)
174 # my_mock.should_receive(:sym).and_yield(values,to,yield).and_yield(some,other,values,this,time)
175 # # for methods that yield to a block multiple times
176 #
177 # Any of these responses can be applied to a stub as well, but stubs do
178 # not support any qualifiers about the message received (i.e. you can't specify arguments
179 # or receive counts):
180 #
181 # my_mock.stub!(:sym).and_return(value)
182 # my_mock.stub!(:sym).and_return(value1, value2, value3)
183 # my_mock.stub!(:sym).and_raise(error)
184 # my_mock.stub!(:sym).and_throw(:sym)
185 # my_mock.stub!(:sym).and_yield(values,to,yield)
186 # my_mock.stub!(:sym).and_yield(values,to,yield).and_yield(some,other,values,this,time)
187 #
188 # == Arbitrary Handling
189 #
190 # Once in a while you'll find that the available expectations don't solve the
191 # particular problem you are trying to solve. Imagine that you expect the message
192 # to come with an Array argument that has a specific length, but you don't care
193 # what is in it. You could do this:
194 #
195 # my_mock.should_receive(:sym) do |arg|
196 # arg.should be_an_istance_of(Array)
197 # arg.length.should == 7
198 # end
199 #
200 # Note that this would fail if the number of arguments received was different from
201 # the number of block arguments (in this case 1).
202 #
203 # == Combining Expectation Details
204 #
205 # Combining the message name with specific arguments, receive counts and responses
206 # you can get quite a bit of detail in your expectations:
207 #
208 # my_mock.should_receive(:<<).with("illegal value").once.and_raise(ArgumentError)
209 module Mocks
210 end
211end