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 +62 -175
- data/Rakefile +19 -1
- data/doc/GoogleExample.rdoc +57 -27
- data/doc/examples/rspec_examples_spec.rdoc +245 -0
- data/doc/examples/test_unit_examples_test.rdoc +241 -0
- data/doc/releases/flexmock-1.0.0.rdoc +2 -0
- data/lib/flexmock/spy_describers.rb +1 -1
- data/lib/flexmock/version.rb +0 -2
- data/test/assert_spy_called_test.rb +3 -3
- data/test/rspec_integration/spy_example_spec.rb +6 -6
- data/test/spys_test.rb +15 -0
- metadata +9 -5
data/README.rdoc
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
= Flex Mock -- Making
|
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
|
6
|
+
Version :: 1.0.0
|
7
7
|
|
8
8
|
= Links
|
9
9
|
|
10
|
-
<b>Documents</b>
|
11
|
-
<b>RubyGems</b>
|
12
|
-
<b>Source</b>
|
13
|
-
<b>Bug Reports
|
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
|
-
*
|
185
|
-
*
|
186
|
-
*
|
187
|
-
*
|
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
|
-
|
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
|
-
|
1062
|
-
|
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
|
-
|
1066
|
-
|
1067
|
-
|
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
|
data/doc/GoogleExample.rdoc
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
= Extended FlexMock Example Using Google4R
|
2
2
|
|
3
|
-
Google4R is a simple Ruby wrapper around the Google APIs.
|
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.
|
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
|
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
|
131
|
-
avoid talking to external resources such as databases and web
|
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+
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
@@ -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
|
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])
|
data/lib/flexmock/version.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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:
|
5
|
-
version: 1.0.0
|
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-
|
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:
|
157
|
+
version: "0"
|
154
158
|
requirements: []
|
155
159
|
|
156
160
|
rubyforge_project:
|