flexmock 1.0.0.beta.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,16 +1,16 @@
1
- = Flex Mock -- Making Mock Easy
1
+ = Flex Mock -- Making Mocking Easy
2
2
 
3
3
  FlexMock is a simple, but flexible, mock object library for Ruby unit
4
4
  testing.
5
5
 
6
- Version :: 1.0.0.beta.4
6
+ Version :: 1.0.0
7
7
 
8
8
  = Links
9
9
 
10
- <b>Documents</b> :: http://flexmock.rubyforge.org
11
- <b>RubyGems</b> :: Install with: <b>gem install flexmock</b>
12
- <b>Source</b> :: https://github.com/jimweirich/flexmock
13
- <b>Bug Reports and Issue Tracking</b> :: https://github.com/jimweirich/flexmock/issues
10
+ <b>Documents</b> :: http://flexmock.rubyforge.org
11
+ <b>RubyGems</b> :: Install with: <b>gem install flexmock</b>
12
+ <b>Source</b> :: https://github.com/jimweirich/flexmock
13
+ <b>Bug Reports / Issue Tracking</b> :: https://github.com/jimweirich/flexmock/issues
14
14
 
15
15
  == Installation
16
16
 
@@ -181,10 +181,11 @@ FlexMock::MockContainer#flexmock for more details.
181
181
 
182
182
  * should_receive
183
183
  * new_instances
184
- * any_instance (note: deprecated)
185
- * mock
186
- * mock_teardown
187
- * mock_setup
184
+ * flexmock_get
185
+ * flexmock_teardown
186
+ * flexmock_verify
187
+ * flexmock_received?
188
+ * flexmock_calls
188
189
 
189
190
  * <b>mock = flexmock(...) { |mock| mock.should_receive(...) }</b>
190
191
 
@@ -664,6 +665,7 @@ library in the <code>Mocha</code> project.
664
665
 
665
666
  FlexMock supports spy-like mocks as well as the traditional mocks.
666
667
 
668
+ # In Test::Unit / MiniTest
667
669
  class TestDogBarking < Test::Unit::TestCase
668
670
  def test_dog
669
671
  dog = flexmock(:on, Dog)
@@ -672,6 +674,44 @@ FlexMock supports spy-like mocks as well as the traditional mocks.
672
674
  end
673
675
  end
674
676
 
677
+ # In RSpec
678
+ describe Dog do
679
+ let(:dog) { flexmock(:on, Dog) }
680
+ it "barks loudly" do
681
+ dog.bark("loud")
682
+ dog.should have_received(:bark).with("loud")
683
+ end
684
+ end
685
+
686
+ Since spies are verified after the code under test is run, they fit
687
+ very nicely with the Given/When/Then technique of specification. Here
688
+ is the above RSpec example using the rspec-given gem:
689
+
690
+ require 'rspec/given'
691
+
692
+ describe Dog do
693
+ Given(:dog) { flexmock(:on, Dog) }
694
+
695
+ context "when barking loudly" do
696
+ When { dog.bark("loud") }
697
+ Then { dog.should have_received(:bark).with("loud") }
698
+ end
699
+ end
700
+
701
+ *NOTE:* You can only spy on methods that are mocked or stubbed. That's
702
+ not a problem with regular mocks, but normal methods on partial
703
+ objects will not be recorded.
704
+
705
+ You can get around this limitation by stubbing the method in question
706
+ on the normal mock, and then specifying <code>pass_thru</code>.
707
+ Assuming <code.:bark</code> is a normal method on a Dog object, then
708
+ the following allows for spying on <code>:bark</code>.
709
+
710
+ dog = Dog.new
711
+ flexmock(dog).should_receive(:bark).pass_thru
712
+ # ...
713
+ dog.should have_received(:bark)
714
+
675
715
  ==== Asserting Spy Methods are Called (Test::Unit / MiniTest)
676
716
 
677
717
  FlexMock provied a custom assertion method for use with Test::Unit and
@@ -909,173 +949,14 @@ beforehand.
909
949
 
910
950
  == Examples
911
951
 
912
- === Create a simple mock object that returns a value for a set of method calls
913
-
914
- require 'flexmock/test_unit'
915
-
916
- class TestSimple < Test::Unit::TestCase
917
- def test_simple_mock
918
- m = flexmock(:pi => 3.1416, :e => 2.71)
919
- assert_equal 3.1416, m.pi
920
- assert_equal 2.71, m.e
921
- end
922
- end
923
-
924
- === Create a mock object that returns an undefined object for method calls
925
-
926
- require 'flexmock/test_unit'
927
-
928
- class TestUndefined < Test::Unit::TestCase
929
- def test_undefined_values
930
- m = flexmock("mock")
931
- m.should_receive(:divide_by).with(0).
932
- and_return_undefined
933
- assert_equal FlexMock.undefined, m.divide_by(0)
934
- end
935
- end
936
-
937
- === Expect multiple queries and a single update
938
-
939
- Multiple calls to the query method will be allows, and calls may have any
940
- argument list. Each call to query will return the three element array [1, 2,
941
- 3]. The call to update must have a specific argument of 5.
942
-
943
- require 'flexmock/test_unit'
944
-
945
- class TestDb < Test::Unit::TestCase
946
- def test_db
947
- db = flexmock('db')
948
- db.should_receive(:query).and_return([1,2,3])
949
- db.should_receive(:update).with(5).and_return(nil).once
950
- # test code here
951
- end
952
- end
953
-
954
- === Expect all queries before any updates
955
-
956
- (This and following examples assume that the 'flexmock/test_unit' file has
957
- been required.)
958
-
959
- All the query message must occur before any of the update messages.
960
-
961
- def test_query_and_update
962
- db = flexmock('db')
963
- db.should_receive(:query).and_return([1,2,3]).ordered
964
- db.should_receive(:update).and_return(nil).ordered
965
- # test code here
966
- end
967
-
968
- === Expect several queries with different parameters
969
-
970
- The queries should happen after startup but before finish. The
971
- queries themselves may happen in any order (because they are in the
972
- same order group). The first two queries should happen exactly once,
973
- but the third query (which matches any query call with a four
974
- character parameter) may be called multiple times (but at least once).
975
- Startup and finish must also happen exactly once.
976
-
977
- Also note that we use the <code>with</code> method to match different
978
- argument values to figure out what value to return.
979
-
980
- def test_ordered_queries
981
- db = flexmock('db')
982
- db.should_receive(:startup).once.ordered
983
- db.should_receive(:query).with("CPWR").and_return(12.3).
984
- once.ordered(:queries)
985
- db.should_receive(:query).with("MSFT").and_return(10.0).
986
- once.ordered(:queries)
987
- db.should_receive(:query).with(/^....$/).and_return(3.3).
988
- at_least.once.ordered(:queries)
989
- db.should_receive(:finish).once.ordered
990
- # test code here
991
- end
992
-
993
- === Same as above, but using the Record Mode interface
994
-
995
- The record mode interface offers much the same features as the
996
- <code>should_receive</code> interface introduced so far, but it allows
997
- the messages to be sent directly to a recording object rather than be
998
- specified indirectly using a symbol.
999
-
1000
- def test_ordered_queries_in_record_mode
1001
- db = flexmock('db')
1002
- db.should_expect do |rec|
1003
- rec.startup.once.ordered
1004
- rec.query("CPWR") { 12.3 }.once.ordered(:queries)
1005
- rec.query("MSFT") { 10.0 }.once.ordered(:queries)
1006
- rec.query(/^....$/) { 3.3 }.at_least.once.ordered(:queries)
1007
- rec.finish.once.ordered
1008
- end
1009
- # test code here using +db+.
1010
- end
1011
-
1012
- === Using Record Mode to record a known, good algorithm for testing
1013
-
1014
- Record mode is nice when you have a known, good algorithm that can use
1015
- a recording mock object to record the steps. Then you compare the
1016
- execution of a new algorithm to behavior of the old using the recorded
1017
- expectations in the mock. For this you probably want to put the
1018
- recorder in _strict_ mode so that the recorded expectations use exact
1019
- matching on argument lists, and strict ordering of the method calls.
1020
-
1021
- <b>Note:</b> This is most useful when there are no queries on the mock
1022
- objects, because the query responses cannot be programmed into the
1023
- recorder object.
1024
-
1025
- def test_build_xml
1026
- builder = flexmock('builder')
1027
- builder.should_expect do |rec|
1028
- rec.should_be_strict
1029
- known_good_way_to_build_xml(rec) # record the messages
1030
- end
1031
- new_way_to_build_xml(builder) # compare to new way
1032
- end
1033
-
1034
- === Expect multiple calls, returning a different value each time
1035
-
1036
- Sometimes you need to return different values for each call to a
1037
- mocked method. This example shifts values out of a list for this
1038
- effect.
1039
-
1040
- def test_multiple_gets
1041
- file = flexmock('file')
1042
- file.should_receive(:gets).with_no_args.
1043
- and_return("line 1\n", "line 2\n")
1044
- # test code here
1045
- end
1046
-
1047
- === Ignore uninteresting messages
1048
-
1049
- Generally you need to mock only those methods that return an
1050
- interesting value or wish to assert were sent in a particular manner.
1051
- Use the <code>should_ignore_missing</code> method to turn on missing
1052
- method ignoring.
1053
-
1054
- def test_an_important_message
1055
- m = flexmock('m')
1056
- m.should_receive(:an_important_message).and_return(1).once
1057
- m.should_ignore_missing
1058
- # test code here
1059
- end
952
+ Refer to the following documents for examples of using FlexMock:
1060
953
 
1061
- When <code>should_ignore_missing</code> is enabled, ignored missing
1062
- methods will return an undefined object. Any operation on the
1063
- undefined object will return the undefined object.
954
+ * {RSpec Examples}[link:doc/examples/rspec_examples_spec_rdoc.html]
955
+ * {Test::Unit / MiniTest Examples}[link:doc/examples/test_unit_examples_test_rdoc.html]
1064
956
 
1065
- === Mock just one method on an existing object
1066
-
1067
- The Portfolio class calculate the value of a set of stocks by talking
1068
- to a quote service via a web service. Since we don't want to use a
1069
- real web service in our unit tests, we will mock the quote service.
1070
-
1071
- def test_portfolio_value
1072
- flexmock(QuoteService).new_instances do |m|
1073
- m.should_receive(:quote).and_return(100)
1074
- end
1075
- port = Portfolio.new
1076
- value = port.value # Portfolio calls QuoteService.quote
1077
- assert_equal 100, value
1078
- end
957
+ *NOTE:* <em>If the above links are not working, you probably need to
958
+ read the documents from the {documentation
959
+ site}[http://flexmock.rubyforge.org]</em>
1079
960
 
1080
961
  == License
1081
962
 
@@ -1091,6 +972,12 @@ above copyright notice is included.
1091
972
  Author:: Jim Weirich <jim.weirich@gmail.com>
1092
973
  Requires:: Ruby 1.9.2 or later (Earlier versions of Flexmock may work with earlier versions of Ruby)
1093
974
 
975
+ == See Also
976
+
977
+ If you like the spy capability of FlexMock, you should check out the
978
+ rspec-given gem (http://rubygems.org/gems/rspec-given) that allows you
979
+ to use Given/When/Then statements in you specifications.
980
+
1094
981
  == Warranty
1095
982
 
1096
983
  This software is provided "as is" and without any express or
data/Rakefile CHANGED
@@ -23,6 +23,11 @@ load './lib/flexmock/version.rb'
23
23
 
24
24
  PKG_VERSION = FlexMock::VERSION
25
25
 
26
+ EXAMPLE_RB = FileList['doc/examples/*.rb']
27
+ EXAMPLE_DOC = EXAMPLE_RB.ext('rdoc')
28
+
29
+ CLOBBER.include(EXAMPLE_DOC)
30
+
26
31
  PKG_FILES = FileList[
27
32
  '[A-Z]*',
28
33
  'lib/**/*.rb',
@@ -36,7 +41,7 @@ RDOC_FILES = FileList[
36
41
  'CHANGES',
37
42
  'lib/**/*.rb',
38
43
  'doc/**/*.rdoc',
39
- ]
44
+ ] + EXAMPLE_DOC
40
45
 
41
46
  task :default => [:test_all, :rspec]
42
47
  task :test_all => [:test]
@@ -84,6 +89,19 @@ file "html/index.html" => ["Rakefile"] + RDOC_FILES do
84
89
  sh "rdoc -o html --title FlexMock --line-numbers -m README.rdoc #{RDOC_FILES}"
85
90
  end
86
91
 
92
+ EXAMPLE_RB.zip(EXAMPLE_DOC).each do |source, target|
93
+ file target => source do
94
+ open(source, "r") do |ins|
95
+ open(target, "w") do |outs|
96
+ outs.puts "= FlexMock Examples"
97
+ ins.each do |line|
98
+ outs.puts " #{line}"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
87
105
  file "README.rdoc" => ["Rakefile", "lib/flexmock/version.rb"] do
88
106
  ruby %{-i.bak -pe '$_.sub!(/^Version *:: *((\\d+|beta|rc)\\.)+\\d+ *$/i, "Version :: #{PKG_VERSION}")' README.rdoc} # "
89
107
  end
@@ -1,6 +1,8 @@
1
1
  = Extended FlexMock Example Using Google4R
2
2
 
3
- Google4R is a simple Ruby wrapper around the Google APIs. In this extended example, we will use FlexMock to test software that uses the Google APIs, without every communicating with Google itself.
3
+ Google4R is a simple Ruby wrapper around the Google APIs. In this
4
+ extended example, we will use FlexMock to test software that uses the
5
+ Google APIs, without every communicating with Google itself.
4
6
 
5
7
  == Purchase.rb
6
8
 
@@ -38,9 +40,11 @@ talking to the Google APIs. The config object given to the Purchase
38
40
  initializer is simply a hash of values defining the merchant_id, merchant_key
39
41
  and sandbox flag. To use the real Google checkout APIs, you will need to
40
42
  obtains a merchant id and key from Google. Since we will be mocking the Google
41
- interaction, we can use dummy values in our test.
43
+ interaction, we can use dummy values in our test.
42
44
 
43
- The tax table factory is required by the Google4R software. We provide the following simplified one. Read the Google API documents for more information.
45
+ The tax table factory is required by the Google4R software. We provide
46
+ the following simplified one. Read the Google API documents for more
47
+ information.
44
48
 
45
49
  class TestTaxTableFactory
46
50
  def effective_tax_tables_at(time)
@@ -49,12 +53,14 @@ The tax table factory is required by the Google4R software. We provide the foll
49
53
  tax_free_table.create_rule do |rule|
50
54
  rule.area = UsCountryArea.new(UsCountryArea::ALL)
51
55
  rule.rate = 0.0
52
- end
56
+ end
53
57
  return [tax_free_table]
54
58
  end
55
59
  end
56
60
 
57
- +Item+ is simply an ActiveRecord class that we are using to hold our purchase item information. It should respond to the +name+, +description+ and +unit_price+ messages.
61
+ +Item+ is simply an ActiveRecord class that we are using to hold our
62
+ purchase item information. It should respond to the +name+,
63
+ +description+ and +unit_price+ messages.
58
64
 
59
65
  == Testing Without Using External Resources
60
66
 
@@ -108,15 +114,15 @@ Here is the complete unit test:
108
114
  :name => "Deschutes",
109
115
  :description => "Deschutes model Guitar",
110
116
  :unit_price => Money.new(2400.00)))
111
-
117
+
112
118
  flexmock(Google4R::Checkout::CheckoutCommand).new_instances do |instance|
113
119
  instance.should_receive(:send_to_google_checkout).once.
114
120
  and_return(flexmock(:redirect_url => "http://google.response.url"))
115
121
  end
116
122
 
117
123
  # Execute
118
- p = Purchase.new({
119
- :merchant_id => 'dummy_id',
124
+ p = Purchase.new({
125
+ :merchant_id => 'dummy_id',
120
126
  :merchant_key => 'dummy_key',
121
127
  :use_sandbox => true })
122
128
  url = p.purchase(1)
@@ -124,27 +130,37 @@ Here is the complete unit test:
124
130
  # Assert
125
131
  assert_equal "http://google.response.url", url
126
132
  end
127
-
133
+
128
134
  == Testing the Details
129
135
 
130
- The above test is fine as far as it goes. It demonstrates how to use mocks to
131
- avoid talking to external resources such as databases and web services. But as a unit test, it is sorely lacking in several areas.
136
+ The above test is fine as far as it goes. It demonstrates how to use
137
+ mocks to avoid talking to external resources such as databases and web
138
+ services. But as a unit test, it is sorely lacking in several areas.
132
139
 
133
- All the test really demonstrates is that the +send_to_google_checkout+ method is called. There are no tests to ensure that the right item descriptions and prices are correctly stored in the cart. In fact, if we rewrote the purchase method as follows:
140
+ All the test really demonstrates is that the +send_to_google_checkout+
141
+ method is called. There are no tests to ensure that the right item
142
+ descriptions and prices are correctly stored in the cart. In fact, if
143
+ we rewrote the purchase method as follows:
134
144
 
135
145
  def purchase(item_id, quantity=1)
136
146
  @frontend.create_checkout_command.send_to_google_checkout.redirect_url
137
- end
147
+ end
138
148
 
139
- it would still pass the unit test we designed, even though the rewrite is obviously an incorrect implementation.
149
+ it would still pass the unit test we designed, even though the rewrite
150
+ is obviously an incorrect implementation.
140
151
 
141
152
  A more complete test is a bit more complicated. Here are the details.
142
153
 
143
154
  === Mocking Active Record
144
155
 
145
- Our incorrect version of purchase never calls the +find+ method of Item. We can easily test for that by adding a +once+ constraint one that mock specification. Since find is a read-only method, we don't really care if it is called multiple times, as long as it is called at least one time, so we will add an +at_least+ modifier as well.
156
+ Our incorrect version of purchase never calls the +find+ method of
157
+ Item. We can easily test for that by adding a +once+ constraint one
158
+ that mock specification. Since find is a read-only method, we don't
159
+ really care if it is called multiple times, as long as it is called at
160
+ least one time, so we will add an +at_least+ modifier as well.
146
161
 
147
- Finally, we are going to break the guitar mock out into its own declaration. The reason will become obvious in a bit.
162
+ Finally, we are going to break the guitar mock out into its own
163
+ declaration. The reason will become obvious in a bit.
148
164
 
149
165
  mock_guitar = flexmock("guitar",
150
166
  :name => "Deschutes",
@@ -156,11 +172,19 @@ Finally, we are going to break the guitar mock out into its own declaration. Th
156
172
 
157
173
  === Mocking a Cart Item
158
174
 
159
- The next bit is a wee bit complicated, but we will handle it a little bit at a time so that it doesn't become overwhelming.
175
+ The next bit is a wee bit complicated, but we will handle it a little
176
+ bit at a time so that it doesn't become overwhelming.
160
177
 
161
- There are three main objects in the Google checkout API that we deal with in the next section.: (1) the checkout command object returned by the front end, (2) the cart object returned by the checkout command, and (3) the item passed to the block in the +create_item+ call.
178
+ There are three main objects in the Google checkout API that we deal
179
+ with in the next section.: (1) the checkout command object returned by
180
+ the front end, (2) the cart object returned by the checkout command,
181
+ and (3) the item passed to the block in the +create_item+ call.
162
182
 
163
- We will tackle them in reverse order, starting with the item objects given to the +create_item+ block. The item must respond to four attribute assignments. This is straightforward to mock, just make sure you include the +once+ constraint so that the assignments are required.
183
+ We will tackle them in reverse order, starting with the item objects
184
+ given to the +create_item+ block. The item must respond to four
185
+ attribute assignments. This is straightforward to mock, just make sure
186
+ you include the +once+ constraint so that the assignments are
187
+ required.
164
188
 
165
189
  mock_item = flexmock("item")
166
190
  mock_item.should_receive(:name=).with(mock_guitar.name).once
@@ -168,18 +192,24 @@ We will tackle them in reverse order, starting with the item objects given to th
168
192
  mock_item.should_receive(:unit_price=).with(mock_guitar.unit_price).once
169
193
  mock_item.should_receive(:quantity=).with(1).once
170
194
 
171
- Notice how we used the mock_guitar object defined earlier to provide values in the +with+ constraint. This way we don't have to repeat the explicit strings and values we are checking. (Keep it DRY!).
195
+ Notice how we used the mock_guitar object defined earlier to provide
196
+ values in the +with+ constraint. This way we don't have to repeat the
197
+ explicit strings and values we are checking. (Keep it DRY!).
172
198
 
173
199
  === Mocking the Cart
174
200
 
175
- The mock cart object will pass the mock_item to a block when the +create_item+ method is called. We specify that with the following:
201
+ The mock cart object will pass the mock_item to a block when the
202
+ +create_item+ method is called. We specify that with the following:
176
203
 
177
204
  mock_cart = flexmock("cart")
178
205
  mock_cart.should_receive(:create_item).with(Proc).once.and_return { |block|
179
206
  block.call(mock_item)
180
207
  }
181
208
 
182
- FlexMock objects can handle blocks passed to them by treating them as the final object in the calling list. Use +Proc+ in the +with+ constraint to match the block and then invoke the block explicitly via <tt>block.call(...)</tt> in the +and_return+ specification.
209
+ FlexMock objects can handle blocks passed to them by treating them as
210
+ the final object in the calling list. Use +Proc+ in the +with+
211
+ constraint to match the block and then invoke the block explicitly via
212
+ <tt>block.call(...)</tt> in the +and_return+ specification.
183
213
 
184
214
  === Mocking the Checkout Command
185
215
 
@@ -223,8 +253,8 @@ Here is the complete detailed version of the test method.
223
253
  end
224
254
 
225
255
  # Execute
226
- p = Purchase.new({
227
- :merchant_id => 'dummy_id',
256
+ p = Purchase.new({
257
+ :merchant_id => 'dummy_id',
228
258
  :merchant_key => 'dummy_key',
229
259
  :use_sandbox => true })
230
260
  url = p.purchase(1)
@@ -253,9 +283,9 @@ Perhaps, but using mock objects have several definite advantages:
253
283
  your code correctly handle the case where you get an exception when
254
284
  connecting to google? Mocks can easily create those error conditions that
255
285
  are difficult to achieve with real objects.
256
-
286
+
257
287
  E.g.
258
-
288
+
259
289
  instance.should_receive(:send_to_google_checkout).once.
260
290
  and_return { raise Google4R::Checkout::GoogleCheckoutError }
261
291
 
@@ -272,4 +302,4 @@ expect it to. We don't actually care about the Google4R software itself in
272
302
  this test case (presumably we do have tests that cover Google4R, but those are
273
303
  different tests).
274
304
 
275
- In the end, mock objects are a power tool to have in your testing toolbox.
305
+ In the end, mock objects are a powerful tool to have in your testing toolbox.
@@ -0,0 +1,245 @@
1
+ = FlexMock Examples
2
+ RSpec.configure do |config|
3
+ config.mock_with :flexmock
4
+ end
5
+
6
+ describe "Simple Spec" do
7
+
8
+ # Simple stubbing of some methods
9
+
10
+ it "stubs a couple of methods" do
11
+ m = flexmock(:pi => 3.1416, :e => 2.71)
12
+ m.pi.should == 3.1416
13
+ m.e.should == 2.71
14
+ end
15
+ end
16
+
17
+
18
+ describe "Returning Undefined" do
19
+
20
+ # Create a mock object that returns an undefined object for method calls
21
+
22
+ it "returns undefined values" do
23
+ m = flexmock("mock")
24
+ m.should_receive(:divide_by).with(0).
25
+ and_return_undefined
26
+
27
+ m.divide_by(0).should == FlexMock.undefined
28
+ end
29
+ end
30
+
31
+ describe "Multiple Queries and Single Updates" do
32
+
33
+ # Expect multiple queries and a single update
34
+
35
+ # Multiple calls to the query method will be allows, and calls may
36
+ # have any argument list. Each call to query will return the three
37
+ # element array [1, 2, 3]. The call to update must have a specific
38
+ # argument of 5.
39
+
40
+ it "queries the db" do
41
+ db = flexmock('db')
42
+ db.should_receive(:query).and_return([1,2,3])
43
+ db.should_receive(:update).with(5).and_return(nil).once
44
+
45
+ # Test Code
46
+
47
+ db.query
48
+ db.update(5)
49
+ end
50
+ end
51
+
52
+ describe "Ordered Mocks" do
53
+
54
+ # Expect all queries before any updates
55
+
56
+ # All the query message must occur before any of the update
57
+ # messages.
58
+
59
+ it "queries and updates the database" do
60
+ db = flexmock('db')
61
+ db.should_receive(:query).and_return([1,2,3]).ordered
62
+ db.should_receive(:update).and_return(nil).ordered
63
+
64
+ # test code here
65
+
66
+ db.query
67
+ db.update
68
+ end
69
+ end
70
+
71
+ describe "Ordered Mocks" do
72
+
73
+ # Expect several queries with different parameters
74
+
75
+ # The queries should happen after startup but before finish. The
76
+ # queries themselves may happen in any order (because they are in
77
+ # the same order group). The first two queries should happen exactly
78
+ # once, but the third query (which matches any query call with a
79
+ # four character parameter) may be called multiple times (but at
80
+ # least once). Startup and finish must also happen exactly once.
81
+
82
+ # Also note that we use the <code>with</code> method to match
83
+ # different argument values to figure out what value to return.
84
+
85
+ it "queries the database in a particular order" do
86
+ db = flexmock('db')
87
+ db.should_receive(:startup).once.ordered
88
+ db.should_receive(:query).with("CPWR").and_return(12.3).
89
+ once.ordered(:queries)
90
+ db.should_receive(:query).with("MSFT").and_return(10.0).
91
+ once.ordered(:queries)
92
+ db.should_receive(:query).with(/^....$/).and_return(3.3).
93
+ at_least.once.ordered(:queries)
94
+ db.should_receive(:finish).once.ordered
95
+
96
+ # Test Code
97
+
98
+ db.startup
99
+ db.query("MSFT")
100
+ db.query("XYZY")
101
+ db.query("CPWR")
102
+ db.finish
103
+ end
104
+ end
105
+
106
+ describe "Ordered Mocks" do
107
+
108
+ # Same as above, but using the Record Mode interface
109
+
110
+ # The record mode interface offers much the same features as the
111
+ # <code>should_receive</code> interface introduced so far, but it
112
+ # allows the messages to be sent directly to a recording object
113
+ # rather than be specified indirectly using a symbol.
114
+
115
+
116
+ it "records the queries for replay" do
117
+ db = flexmock('db')
118
+ db.should_expect do |rec|
119
+ rec.startup.once.ordered
120
+ rec.query("CPWR") { 12.3 }.once.ordered(:queries)
121
+ rec.query("MSFT") { 10.0 }.once.ordered(:queries)
122
+ rec.query(/^....$/) { 3.3 }.at_least.once.ordered(:queries)
123
+ rec.finish.once.ordered
124
+ end
125
+
126
+ # Test Code
127
+
128
+ db.startup
129
+ db.query("MSFT")
130
+ db.query("XYZY")
131
+ db.query("CPWR")
132
+ db.finish
133
+ end
134
+ end
135
+
136
+ describe "Record Mode" do
137
+
138
+ # Using Record Mode to record a known, good algorithm for testing
139
+
140
+ # Record mode is nice when you have a known, good algorithm that can
141
+ # use a recording mock object to record the steps. Then you compare
142
+ # the execution of a new algorithm to behavior of the old using the
143
+ # recorded expectations in the mock. For this you probably want to
144
+ # put the recorder in _strict_ mode so that the recorded
145
+ # expectations use exact matching on argument lists, and strict
146
+ # ordering of the method calls.
147
+
148
+ # <b>Note:</b> This is most useful when there are no queries on the
149
+ # mock objects, because the query responses cannot be programmed
150
+ # into the recorder object.
151
+
152
+ it "compares a know algorithm with a new algorithm" do
153
+ builder = flexmock('builder')
154
+ builder.should_expect do |rec|
155
+ rec.should_be_strict
156
+ known_good_way_to_build_xml(rec) # record the messages
157
+ end
158
+ new_way_to_build_xml(builder) # compare to new way
159
+ end
160
+
161
+ def known_good_way_to_build_xml(builder)
162
+ builder.person
163
+ end
164
+
165
+ def new_way_to_build_xml(builder)
166
+ builder.person
167
+ end
168
+
169
+ end
170
+
171
+ describe "Multiple Return Values" do
172
+
173
+ # Expect multiple calls, returning a different value each time
174
+
175
+ # Sometimes you need to return different values for each call to a
176
+ # mocked method. This example shifts values out of a list for this
177
+ # effect.
178
+
179
+ it "returns multiple values" do
180
+ file = flexmock('file')
181
+ file.should_receive(:gets).with_no_args.
182
+ and_return("line 1\n", "line 2\n")
183
+
184
+ # test code here
185
+
186
+ file.gets # returns "line 1"
187
+ file.gets # returns "line 2"
188
+ end
189
+ end
190
+
191
+ describe "Ignore Unimportant Messages" do
192
+
193
+ # Ignore uninteresting messages
194
+
195
+ # Generally you need to mock only those methods that return an
196
+ # interesting value or wish to assert were sent in a particular
197
+ # manner. Use the <code>should_ignore_missing</code> method to turn
198
+ # on missing method ignoring.
199
+
200
+ it "ignores unimportant messages" do
201
+ m = flexmock('m')
202
+ m.should_receive(:an_important_message).and_return(1).once
203
+ m.should_ignore_missing
204
+
205
+ # Test Code
206
+
207
+ m.an_important_message
208
+ m.an_unimportant_message
209
+ end
210
+
211
+ # When <code>should_ignore_missing</code> is enabled, ignored
212
+ # missing methods will return an undefined object. Any operation on
213
+ # the undefined object will return the undefined object.
214
+
215
+ end
216
+
217
+
218
+ describe "Partial Mocks" do
219
+
220
+ # Mock just one method on an existing object
221
+
222
+ # The Portfolio class calculate the value of a set of stocks by
223
+ # talking to a quote service via a web service. Since we don't want
224
+ # to use a real web service in our unit tests, we will mock the
225
+ # quote service.
226
+
227
+ it "returns the portfolio value" do
228
+ flexmock(QuoteService).new_instances do |m|
229
+ m.should_receive(:quote).and_return(100)
230
+ end
231
+ port = Portfolio.new
232
+ value = port.value # Portfolio calls QuoteService.quote
233
+ value.should == 100
234
+ end
235
+
236
+ class QuoteService
237
+ end
238
+
239
+ class Portfolio
240
+ def value
241
+ qs = QuoteService.new
242
+ qs.quote
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,241 @@
1
+ = FlexMock Examples
2
+ require 'flexmock/test_unit'
3
+
4
+ class TestSimple < Test::Unit::TestCase
5
+
6
+ # Simple stubbing of some methods
7
+
8
+ def test_simple_mock
9
+ m = flexmock(:pi => 3.1416, :e => 2.71)
10
+ assert_equal 3.1416, m.pi
11
+ assert_equal 2.71, m.e
12
+ end
13
+ end
14
+
15
+
16
+ class TestUndefined < Test::Unit::TestCase
17
+
18
+ # Create a mock object that returns an undefined object for method calls
19
+
20
+ def test_undefined_values
21
+ m = flexmock("mock")
22
+ m.should_receive(:divide_by).with(0).
23
+ and_return_undefined
24
+ assert_equal FlexMock.undefined, m.divide_by(0)
25
+ end
26
+ end
27
+
28
+ class TestDb < Test::Unit::TestCase
29
+
30
+ # Expect multiple queries and a single update
31
+
32
+ # Multiple calls to the query method will be allows, and calls may
33
+ # have any argument list. Each call to query will return the three
34
+ # element array [1, 2, 3]. The call to update must have a specific
35
+ # argument of 5.
36
+
37
+ def test_db
38
+ db = flexmock('db')
39
+ db.should_receive(:query).and_return([1,2,3])
40
+ db.should_receive(:update).with(5).and_return(nil).once
41
+
42
+ # Test Code
43
+
44
+ db.query
45
+ db.update(5)
46
+ end
47
+ end
48
+
49
+ class TestOrdered < Test::Unit::TestCase
50
+
51
+ # Expect all queries before any updates
52
+
53
+ # All the query message must occur before any of the update
54
+ # messages.
55
+
56
+ def test_query_and_update
57
+ db = flexmock('db')
58
+ db.should_receive(:query).and_return([1,2,3]).ordered
59
+ db.should_receive(:update).and_return(nil).ordered
60
+
61
+ # test code here
62
+
63
+ db.query
64
+ db.update
65
+ end
66
+ end
67
+
68
+ class MoreOrdered < Test::Unit::TestCase
69
+
70
+ # Expect several queries with different parameters
71
+
72
+ # The queries should happen after startup but before finish. The
73
+ # queries themselves may happen in any order (because they are in
74
+ # the same order group). The first two queries should happen exactly
75
+ # once, but the third query (which matches any query call with a
76
+ # four character parameter) may be called multiple times (but at
77
+ # least once). Startup and finish must also happen exactly once.
78
+
79
+ # Also note that we use the <code>with</code> method to match
80
+ # different argument values to figure out what value to return.
81
+
82
+ def test_ordered_queries
83
+ db = flexmock('db')
84
+ db.should_receive(:startup).once.ordered
85
+ db.should_receive(:query).with("CPWR").and_return(12.3).
86
+ once.ordered(:queries)
87
+ db.should_receive(:query).with("MSFT").and_return(10.0).
88
+ once.ordered(:queries)
89
+ db.should_receive(:query).with(/^....$/).and_return(3.3).
90
+ at_least.once.ordered(:queries)
91
+ db.should_receive(:finish).once.ordered
92
+
93
+ # Test Code
94
+
95
+ db.startup
96
+ db.query("MSFT")
97
+ db.query("XYZY")
98
+ db.query("CPWR")
99
+ db.finish
100
+ end
101
+ end
102
+
103
+ class EvenMoreOrderedTest < Test::Unit::TestCase
104
+
105
+ # Same as above, but using the Record Mode interface
106
+
107
+ # The record mode interface offers much the same features as the
108
+ # <code>should_receive</code> interface introduced so far, but it
109
+ # allows the messages to be sent directly to a recording object
110
+ # rather than be specified indirectly using a symbol.
111
+
112
+
113
+ def test_ordered_queries_in_record_mode
114
+ db = flexmock('db')
115
+ db.should_expect do |rec|
116
+ rec.startup.once.ordered
117
+ rec.query("CPWR") { 12.3 }.once.ordered(:queries)
118
+ rec.query("MSFT") { 10.0 }.once.ordered(:queries)
119
+ rec.query(/^....$/) { 3.3 }.at_least.once.ordered(:queries)
120
+ rec.finish.once.ordered
121
+ end
122
+
123
+ # Test Code
124
+
125
+ db.startup
126
+ db.query("MSFT")
127
+ db.query("XYZY")
128
+ db.query("CPWR")
129
+ db.finish
130
+ end
131
+ end
132
+
133
+ class RecordedTest < Test::Unit::TestCase
134
+
135
+ # Using Record Mode to record a known, good algorithm for testing
136
+
137
+ # Record mode is nice when you have a known, good algorithm that can
138
+ # use a recording mock object to record the steps. Then you compare
139
+ # the execution of a new algorithm to behavior of the old using the
140
+ # recorded expectations in the mock. For this you probably want to
141
+ # put the recorder in _strict_ mode so that the recorded
142
+ # expectations use exact matching on argument lists, and strict
143
+ # ordering of the method calls.
144
+
145
+ # <b>Note:</b> This is most useful when there are no queries on the
146
+ # mock objects, because the query responses cannot be programmed
147
+ # into the recorder object.
148
+
149
+ def test_build_xml
150
+ builder = flexmock('builder')
151
+ builder.should_expect do |rec|
152
+ rec.should_be_strict
153
+ known_good_way_to_build_xml(rec) # record the messages
154
+ end
155
+ new_way_to_build_xml(builder) # compare to new way
156
+ end
157
+
158
+ def known_good_way_to_build_xml(builder)
159
+ builder.person
160
+ end
161
+
162
+ def new_way_to_build_xml(builder)
163
+ builder.person
164
+ end
165
+
166
+ end
167
+
168
+ class MultipleReturnValueTest < Test::Unit::TestCase
169
+
170
+ # Expect multiple calls, returning a different value each time
171
+
172
+ # Sometimes you need to return different values for each call to a
173
+ # mocked method. This example shifts values out of a list for this
174
+ # effect.
175
+
176
+ def test_multiple_gets
177
+ file = flexmock('file')
178
+ file.should_receive(:gets).with_no_args.
179
+ and_return("line 1\n", "line 2\n")
180
+
181
+ # test code here
182
+
183
+ file.gets # returns "line 1"
184
+ file.gets # returns "line 2"
185
+ end
186
+ end
187
+
188
+ class IgnoreUnimportantMessages < Test::Unit::TestCase
189
+
190
+ # Ignore uninteresting messages
191
+
192
+ # Generally you need to mock only those methods that return an
193
+ # interesting value or wish to assert were sent in a particular
194
+ # manner. Use the <code>should_ignore_missing</code> method to turn
195
+ # on missing method ignoring.
196
+
197
+ def test_an_important_message
198
+ m = flexmock('m')
199
+ m.should_receive(:an_important_message).and_return(1).once
200
+ m.should_ignore_missing
201
+
202
+ # Test Code
203
+
204
+ m.an_important_message
205
+ m.an_unimportant_message
206
+ end
207
+
208
+ # When <code>should_ignore_missing</code> is enabled, ignored
209
+ # missing methods will return an undefined object. Any operation on
210
+ # the undefined object will return the undefined object.
211
+
212
+ end
213
+
214
+ class PartialMockTest < Test::Unit::TestCase
215
+
216
+ # Mock just one method on an existing object
217
+
218
+ # The Portfolio class calculate the value of a set of stocks by
219
+ # talking to a quote service via a web service. Since we don't want
220
+ # to use a real web service in our unit tests, we will mock the
221
+ # quote service.
222
+
223
+ def test_portfolio_value
224
+ flexmock(QuoteService).new_instances do |m|
225
+ m.should_receive(:quote).and_return(100)
226
+ end
227
+ port = Portfolio.new
228
+ value = port.value # Portfolio calls QuoteService.quote
229
+ assert_equal 100, value
230
+ end
231
+
232
+ class QuoteService
233
+ end
234
+
235
+ class Portfolio
236
+ def value
237
+ qs = QuoteService.new
238
+ qs.quote
239
+ end
240
+ end
241
+ end
@@ -29,6 +29,8 @@ a few bug fixes.
29
29
 
30
30
  * Using the documented +singleton_methods+ method.
31
31
 
32
+ * Accidently trying to partial mock a regular mock is now a no-op.
33
+
32
34
  == What is FlexMock?
33
35
 
34
36
  FlexMock is a flexible framework for creating mock object for testing. When
@@ -14,7 +14,7 @@ class FlexMock
14
14
  def describe(spy, sym, args, options, not_clause="")
15
15
  result = "expected "
16
16
  result << call_description(sym, args)
17
- result << " to#{not_clause} be called on "
17
+ result << " to#{not_clause} be received by "
18
18
  result << spy.inspect
19
19
  result << times_description(options[:times])
20
20
  result << block_description(options[:with_block])
@@ -4,8 +4,6 @@ class FlexMock
4
4
  MAJOR = 1,
5
5
  MINOR = 0,
6
6
  BUILD = 0,
7
- BETA = 'beta',
8
- BETAREV = 4,
9
7
  ]
10
8
  end
11
9
 
@@ -34,7 +34,7 @@ class AssertSpyCalledTest < Test::Unit::TestCase
34
34
 
35
35
  def test_assert_rejects_incorrect_args
36
36
  spy.foo(1,2)
37
- messages = assert_fails(/^expected foo\(1, 3\) to be called on <FlexMock:AssertSpyCalledTest::FooBar Mock>/i) do
37
+ messages = assert_fails(/^expected foo\(1, 3\) to be received by <FlexMock:AssertSpyCalledTest::FooBar Mock>/i) do
38
38
  assert_spy_called spy, :foo, 1, 3
39
39
  end
40
40
  end
@@ -49,7 +49,7 @@ class AssertSpyCalledTest < Test::Unit::TestCase
49
49
  def test_assert_rejects_incorrect_type
50
50
  spy.foo
51
51
  spy.foo
52
- assert_fails(/^expected foo\(\) to be called on <FlexMock:AssertSpyCalledTest::FooBar Mock> 3 times/i) do
52
+ assert_fails(/^expected foo\(\) to be received by <FlexMock:AssertSpyCalledTest::FooBar Mock> 3 times/i) do
53
53
  assert_spy_called spy, {times: 3}, :foo
54
54
  end
55
55
  end
@@ -71,7 +71,7 @@ class AssertSpyCalledTest < Test::Unit::TestCase
71
71
 
72
72
  def test_assert_rejects_bad_count_on_any_args
73
73
  spy.foo
74
- assert_fails(/^expected foo\(\.\.\.\) to be called on <FlexMock:AssertSpyCalledTest::FooBar Mock> twice/i) do
74
+ assert_fails(/^expected foo\(\.\.\.\) to be received by <FlexMock:AssertSpyCalledTest::FooBar Mock> twice/i) do
75
75
  assert_spy_called spy, {times: 2}, :foo, :_
76
76
  end
77
77
  end
@@ -31,13 +31,13 @@ describe "Dog" do
31
31
  end
32
32
 
33
33
  it "rejects wag(:foot)" do
34
- should_fail(/^expected wag\(:foot\) to be called on <FlexMock:Dog Mock>/i) do
34
+ should_fail(/^expected wag\(:foot\) to be received by <FlexMock:Dog Mock>/i) do
35
35
  dog.should have_received(:wag).with(:foot)
36
36
  end
37
37
  end
38
38
 
39
39
  it "rejects not wag(:tail)" do
40
- should_fail(/^expected wag\(:foot\) to be called on <FlexMock:Dog Mock>/i) do
40
+ should_fail(/^expected wag\(:foot\) to be received by <FlexMock:Dog Mock>/i) do
41
41
  dog.should_not have_received(:wag).with(:tail)
42
42
  end
43
43
  end
@@ -58,7 +58,7 @@ describe "Dog" do
58
58
  end
59
59
 
60
60
  it "rejects wags(:tail) wrong times value" do
61
- should_fail(/^expected wags\(:tail\) to be called on <FlexMock:Dog Mock>/i) do
61
+ should_fail(/^expected wags\(:tail\) to be received by <FlexMock:Dog Mock>/i) do
62
62
  dog.should have_received(:wags).with(:tail).times(2)
63
63
  end
64
64
  end
@@ -72,7 +72,7 @@ describe "Dog" do
72
72
  end
73
73
 
74
74
  it "rejects an incorrect once" do
75
- should_fail(/^expected wags\(:tail\) to be called on <FlexMock:Dog Mock> once/i) do
75
+ should_fail(/^expected wags\(:tail\) to be received by <FlexMock:Dog Mock> once/i) do
76
76
  dog.should have_received(:wags).with(:tail).once
77
77
  end
78
78
  end
@@ -82,7 +82,7 @@ describe "Dog" do
82
82
  end
83
83
 
84
84
  it "rejects an incorrect twice" do
85
- should_fail(/^expected wags\(:tail\) to be called on <FlexMock:Dog Mock> twice/) do
85
+ should_fail(/^expected wags\(:tail\) to be received by <FlexMock:Dog Mock> twice/) do
86
86
  dog.should have_received(:wags).with(:tail).twice
87
87
  end
88
88
  end
@@ -92,7 +92,7 @@ describe "Dog" do
92
92
  end
93
93
 
94
94
  it "rejects an incorrect never" do
95
- should_fail(/^expected barks\(\) to be called on <FlexMock:Dog Mock> never/i) do
95
+ should_fail(/^expected barks\(\) to be received by <FlexMock:Dog Mock> never/i) do
96
96
  dog.should have_received(:barks).with().never
97
97
  end
98
98
  end
data/test/spys_test.rb CHANGED
@@ -7,6 +7,7 @@ class TestSpys < Test::Unit::TestCase
7
7
 
8
8
  class FooBar
9
9
  def foo
10
+ :foofoo
10
11
  end
11
12
  def bar
12
13
  end
@@ -96,6 +97,20 @@ class TestSpys < Test::Unit::TestCase
96
97
  assert_spy_called @spy, :foo
97
98
  end
98
99
 
100
+ def test_spy_cannot_see_normal_methods
101
+ foo = FooBar.new
102
+ flexmock(foo)
103
+ assert_equal :foofoo, foo.foo
104
+ assert_spy_not_called foo, :foo
105
+ end
106
+
107
+ def test_spy_cannot_see_normal_methods2
108
+ foo = FooBar.new
109
+ flexmock(foo).should_receive(:foo).pass_thru
110
+ assert_equal :foofoo, foo.foo
111
+ assert_spy_called foo, :foo
112
+ end
113
+
99
114
  def test_calling_non_spy_base_methods_is_an_error
100
115
  assert_raise(NoMethodError) do
101
116
  @spy.baz
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flexmock
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: 6
5
- version: 1.0.0.beta.4
4
+ prerelease:
5
+ version: 1.0.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jim Weirich
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-08-22 00:00:00 Z
13
+ date: 2012-08-23 00:00:00 Z
14
14
  dependencies: []
15
15
 
16
16
  description: "\n FlexMock is a extremely simple mock object class compatible\n with the Test::Unit framework. Although the FlexMock's\n interface is simple, it is very flexible.\n "
@@ -22,6 +22,8 @@ extensions: []
22
22
  extra_rdoc_files:
23
23
  - README.rdoc
24
24
  - CHANGES
25
+ - doc/examples/rspec_examples_spec.rdoc
26
+ - doc/examples/test_unit_examples_test.rdoc
25
27
  - doc/GoogleExample.rdoc
26
28
  - doc/releases/flexmock-0.4.0.rdoc
27
29
  - doc/releases/flexmock-0.4.1.rdoc
@@ -106,6 +108,8 @@ files:
106
108
  - test/undefined_test.rb
107
109
  - flexmock.blurb
108
110
  - install.rb
111
+ - doc/examples/rspec_examples_spec.rdoc
112
+ - doc/examples/test_unit_examples_test.rdoc
109
113
  - doc/GoogleExample.rdoc
110
114
  - doc/releases/flexmock-0.4.0.rdoc
111
115
  - doc/releases/flexmock-0.4.1.rdoc
@@ -148,9 +152,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
152
  required_rubygems_version: !ruby/object:Gem::Requirement
149
153
  none: false
150
154
  requirements:
151
- - - ">"
155
+ - - ">="
152
156
  - !ruby/object:Gem::Version
153
- version: 1.3.1
157
+ version: "0"
154
158
  requirements: []
155
159
 
156
160
  rubyforge_project: