matahari 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +35 -1
- data/lib/matahari/debriefing.rb +26 -25
- metadata +7 -2
data/README.rdoc
CHANGED
@@ -16,6 +16,7 @@ you to specify all method calls, including uninteresting ones.
|
|
16
16
|
describe "my object" do
|
17
17
|
obj = MyAwesomeObject.new
|
18
18
|
collaborator = spy(:collaborator)
|
19
|
+
obj.collaborator = collaborator
|
19
20
|
|
20
21
|
obj.my_awesome_method
|
21
22
|
|
@@ -24,11 +25,43 @@ you to specify all method calls, including uninteresting ones.
|
|
24
25
|
|
25
26
|
See also the cucumber feature, easily viewable at http://relishapp.com/Mortice/matahari
|
26
27
|
|
28
|
+
== CONTEXT:
|
29
|
+
|
30
|
+
Traditional mocks require you to put expectations (my_mock.should_receive) before action,
|
31
|
+
potentially with assertions coming after that. They also do stubbing at the same time as
|
32
|
+
setting up expectations (my_mock.should_receive(:something).and_return). These issues
|
33
|
+
lead to less readable tests and a tendency to set an expectation when only a stub is
|
34
|
+
required, or vice versa.
|
35
|
+
|
36
|
+
Test spies present an alternative philosophy to traditional mocking by acting as null
|
37
|
+
objects and then allowing assertions after the fact on method calls they have received.
|
38
|
+
This means that stubbing and asserting on collaborations can be separated and that all
|
39
|
+
assertions in a given test go in the same place.
|
40
|
+
|
41
|
+
The RR project provides test spies, but due to the way it is built (it supports a
|
42
|
+
variety of different double strategies), it requires the user to call 'stub' on any
|
43
|
+
method which will later be asserted on. As @dchemlimsky puts it, this 'adds the need
|
44
|
+
for an extra line, binds these two lines [the stub call and the assertion] together,
|
45
|
+
and generally makes [the test] more difficult to understand.'
|
46
|
+
|
47
|
+
By sticking to spies as a double strategy, matahari is able to avoid the need for a
|
48
|
+
similar call in the setup portion of the test - matahari spies simply collect the
|
49
|
+
details of all messages passed to them and provide a means for inspecting those
|
50
|
+
messages later.
|
51
|
+
|
52
|
+
=== Further reading
|
53
|
+
https://gist.github.com/716640 - Conversation between dchelimsky and myself about Ruby test
|
54
|
+
doubles
|
55
|
+
|
56
|
+
http://dannorth.net/2008/09/14/the-end-of-endotesting/ - Article about mockito, which heavily
|
57
|
+
influenced the creation of Matahari
|
58
|
+
|
27
59
|
== KNOWN ISSUES/TODO:
|
28
60
|
|
29
61
|
* Stubbing implementation is incredibly basic
|
30
62
|
* Not very usable at all for test/unit users (but this is easily fixed with an assert_received method)
|
31
63
|
* No support for argument matchers - arguments must match exactly via == or not at all
|
64
|
+
* We need to be able to remote-control BMWs.
|
32
65
|
|
33
66
|
== INSTALL:
|
34
67
|
|
@@ -36,10 +69,11 @@ See also the cucumber feature, easily viewable at http://relishapp.com/Mortice/m
|
|
36
69
|
|
37
70
|
== ACKNOWLEDGEMENTS:
|
38
71
|
|
39
|
-
* David Chelimsky, for putting up with my
|
72
|
+
* David Chelimsky, for putting up with my robust criticisms of RSpec mocks
|
40
73
|
* Aslak Hellesøy, for giving interesting feedback on an early version
|
41
74
|
* Szczepan Faber, for creating Mockito
|
42
75
|
* Brian Takita, for creating RR
|
76
|
+
* James Adam, for encouraging people to add CONTEXT sections to their READMEs
|
43
77
|
|
44
78
|
== LICENSE:
|
45
79
|
|
data/lib/matahari/debriefing.rb
CHANGED
@@ -1,31 +1,14 @@
|
|
1
1
|
class Debriefing
|
2
|
-
def initialize(
|
3
|
-
@
|
2
|
+
def initialize(expected_call_count = nil)
|
3
|
+
@expected_call_count = expected_call_count
|
4
4
|
end
|
5
5
|
|
6
6
|
def matches?(subject)
|
7
7
|
@subject = subject
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
if @expected_calls
|
13
|
-
checked_number_of_calls = true
|
14
|
-
args_match = @matching_calls == @expected_calls
|
15
|
-
else
|
16
|
-
args_match = @matching_calls > 0
|
17
|
-
end
|
18
|
-
matching = if checked_number_of_calls
|
19
|
-
args_match
|
20
|
-
else
|
21
|
-
method_matched && no_args || args_match
|
22
|
-
end
|
23
|
-
|
24
|
-
if matching
|
25
|
-
true
|
26
|
-
else
|
27
|
-
false
|
28
|
-
end
|
8
|
+
@invocations_of_method = subject.invocations.select {|i| i[:method] == @call_to_verify}
|
9
|
+
verifying_args = @args_to_verify.size != 0
|
10
|
+
|
11
|
+
match_passes?(verifying_args)
|
29
12
|
end
|
30
13
|
|
31
14
|
def failure_message_for_should_not
|
@@ -34,9 +17,9 @@ class Debriefing
|
|
34
17
|
|
35
18
|
def failure_message_for_should
|
36
19
|
if @args_to_verify.size > 0
|
37
|
-
"Spy(:#{@subject.name}) expected to receive :#{@call_to_verify}(#{@args_to_verify.map(&:inspect).join(", ")}) #{prettify_times(@
|
20
|
+
"Spy(:#{@subject.name}) expected to receive :#{@call_to_verify}(#{@args_to_verify.map(&:inspect).join(", ")}) #{prettify_times(@expected_call_count)}, received #{prettify_times(@matching_calls)}"
|
38
21
|
else
|
39
|
-
"Spy(:#{@subject.name}) expected to receive :#{@call_to_verify} #{prettify_times(@
|
22
|
+
"Spy(:#{@subject.name}) expected to receive :#{@call_to_verify} #{prettify_times(@expected_call_count)}, received #{prettify_times(@matching_calls)}"
|
40
23
|
end
|
41
24
|
end
|
42
25
|
|
@@ -59,4 +42,22 @@ class Debriefing
|
|
59
42
|
end
|
60
43
|
end
|
61
44
|
private :prettify_times
|
45
|
+
|
46
|
+
def matching_calls(verifying_args=true)
|
47
|
+
@matching_calls ||= if verifying_args
|
48
|
+
@invocations_of_method.select {|i| i[:args].flatten === @args_to_verify}.size
|
49
|
+
else
|
50
|
+
@invocations_of_method.size
|
51
|
+
end
|
52
|
+
end
|
53
|
+
private :matching_calls
|
54
|
+
|
55
|
+
def match_passes?(verifying_args)
|
56
|
+
if @expected_call_count
|
57
|
+
matching_calls(verifying_args) == @expected_call_count
|
58
|
+
else
|
59
|
+
matching_calls(verifying_args) > 0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
private :match_passes?
|
62
63
|
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: matahari
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Tom Stuart
|
@@ -25,6 +26,7 @@ dependencies:
|
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
28
30
|
segments:
|
29
31
|
- 0
|
30
32
|
version: "0"
|
@@ -38,6 +40,7 @@ dependencies:
|
|
38
40
|
requirements:
|
39
41
|
- - ">="
|
40
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
41
44
|
segments:
|
42
45
|
- 0
|
43
46
|
version: "0"
|
@@ -76,6 +79,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
79
|
requirements:
|
77
80
|
- - ">="
|
78
81
|
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
79
83
|
segments:
|
80
84
|
- 0
|
81
85
|
version: "0"
|
@@ -84,6 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
88
|
requirements:
|
85
89
|
- - ">="
|
86
90
|
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
87
92
|
segments:
|
88
93
|
- 0
|
89
94
|
version: "0"
|