matahari 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.rdoc +35 -1
  2. data/lib/matahari/debriefing.rb +26 -25
  3. 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 'robust' criticisms of RSpec mocks
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
 
@@ -1,31 +1,14 @@
1
1
  class Debriefing
2
- def initialize(expected_calls = nil)
3
- @expected_calls = expected_calls
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
- invocations_matching_method = subject.invocations.select {|i| i[:method] == @call_to_verify}
9
- method_matched = invocations_matching_method.size > 0
10
- no_args = @args_to_verify.size == 0
11
- @matching_calls = invocations_matching_method.select {|i| i[:args].flatten === @args_to_verify}.size
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(@expected_calls)}, received #{prettify_times(@matching_calls)}"
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(@expected_calls)}, received #{prettify_times(@matching_calls)}"
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
- - 1
9
- version: 0.1.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"