verified_double 0.1.1 → 0.2.0
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/CHANGELOG.markdown +12 -0
- data/README.md +25 -14
- data/features/CHANGELOG.markdown +12 -0
- data/features/readme.md +25 -14
- data/features/verified_mocks.feature +4 -2
- data/lib/verified_double.rb +10 -1
- data/lib/verified_double/matchers.rb +2 -2
- data/lib/verified_double/method_signature.rb +5 -5
- data/lib/verified_double/method_signature/boolean_value.rb +9 -0
- data/lib/verified_double/method_signature/class_value.rb +17 -0
- data/lib/verified_double/method_signature/instance_double_value.rb +9 -0
- data/lib/verified_double/method_signature/instance_value.rb +17 -0
- data/lib/verified_double/method_signature/recording_double_class_value.rb +9 -0
- data/lib/verified_double/method_signature/rspec_double_value.rb +9 -0
- data/lib/verified_double/method_signature/value.rb +37 -0
- data/lib/verified_double/method_signatures_report.rb +10 -3
- data/lib/verified_double/parse_method_signature.rb +2 -2
- data/lib/verified_double/recorded_method_signature.rb +9 -0
- data/lib/verified_double/recording_double.rb +13 -4
- data/lib/verified_double/stack_frame.rb +11 -0
- data/lib/verified_double/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/verified_double/matchers_spec.rb +1 -1
- data/spec/verified_double/method_signature/boolean_value_spec.rb +11 -0
- data/spec/verified_double/method_signature/class_value_spec.rb +35 -0
- data/spec/verified_double/method_signature/instance_double_value_spec.rb +17 -0
- data/spec/verified_double/method_signature/instance_value_spec.rb +39 -0
- data/spec/verified_double/method_signature/recording_double_class_value_spec.rb +23 -0
- data/spec/verified_double/method_signature/rspec_double_spec.rb +14 -0
- data/spec/verified_double/method_signature/value_spec.rb +89 -0
- data/spec/verified_double/method_signature_spec.rb +16 -16
- data/spec/verified_double/method_signatures_report_spec.rb +14 -12
- data/spec/verified_double/parse_method_signature_spec.rb +3 -3
- data/spec/verified_double/recorded_method_signature_spec.rb +23 -0
- data/spec/verified_double/recording_double_spec.rb +103 -77
- data/spec/verified_double/stack_frame_spec.rb +15 -0
- data/spec/verified_double_spec.rb +1 -1
- metadata +29 -7
- data/lib/verified_double/method_signature_value.rb +0 -45
- data/spec/unit_helper.rb +0 -16
- data/spec/verified_double/method_signature_value_spec.rb +0 -126
data/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
0.2.0 - 2013-06-30
|
2
|
+
------------------
|
3
|
+
|
4
|
+
* [#4] Add stack frames and relish app link to output.
|
5
|
+
* [#12] RecordingDouble#class should be the class of the object being doubled.
|
6
|
+
* [#16] Fix handling of doubles passed as method signature values.
|
7
|
+
|
8
|
+
Known issues:
|
9
|
+
|
10
|
+
* Stack frames sometimes point to verified_double gem instead of where the mock was recorded.
|
11
|
+
|
12
|
+
|
1
13
|
0.1.1 - 2013-06-26
|
2
14
|
------------------
|
3
15
|
|
data/README.md
CHANGED
@@ -2,34 +2,45 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/gsmendoza/verified_double)
|
4
4
|
|
5
|
-
VerifiedDouble
|
5
|
+
VerifiedDouble is a gem for verifying rspec mocks. The gem works similar to [rspec-fire](https://github.com/xaviershay/rspec-fire). However, instead of checking if the doubled classes respond to the methods, the gem looks for tests confirming if those mocks are valid.
|
6
6
|
|
7
7
|
For example, let's say I mocked the created_at method of a model like this:
|
8
8
|
|
9
9
|
item = VerifiedDouble.of_instance(Item)
|
10
10
|
item.should_receive(:created_at).and_return(Time.now)
|
11
11
|
|
12
|
-
|
13
|
-
running the tests, the gem looks for a test that confirms if you can
|
14
|
-
indeed call #created_at on Item. The test should also ensure that the method
|
15
|
-
returns a Time object. Since this is hard to automate, the gem just looks
|
16
|
-
for a test with a tag saying it verifies that contract:
|
12
|
+
When running the tests, the gem looks for a "contract test" tagged with the method's signature. This test should ensure that calling #created_at on Item will return a Time object.
|
17
13
|
|
18
14
|
it "tests something", verifies_contract: 'Item#created_at()=>Time' do
|
19
15
|
#...
|
20
16
|
end
|
21
17
|
|
22
|
-
If this test does not exist, the gem will complain that the mock is not
|
23
|
-
verified.
|
18
|
+
If this test does not exist, the gem will complain that the mock is not verified.
|
24
19
|
|
25
|
-
|
20
|
+
I got the idea from http://www.infoq.com/presentations/integration-tests-scam, an old (2009) talk that still has some fresh insights on dealing with API changes in your mocked tests.
|
26
21
|
|
27
|
-
|
28
|
-
----------
|
22
|
+
You can learn more about using the gem at https://www.relishapp.com/gsmendoza/verified-double.
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
Actively tested against
|
25
|
+
-----------------------
|
26
|
+
|
27
|
+
* Ruby 1.9.3
|
28
|
+
* RSpec 2.13
|
29
|
+
|
30
|
+
|
31
|
+
Alternatives
|
32
|
+
------------
|
33
|
+
|
34
|
+
[Bogus](https://www.relishapp.com/bogus/bogus/v/0-0-3/docs/) is the first gem to implement contract tests. It doesn't rely on rspec tags to verify contracts, so it's probably a lot smarter than VerifiedDouble :) However, I wasn't able to try it out on my own projects because of its own rr-like mock adapter. But do check it out!
|
35
|
+
|
36
|
+
Caveats
|
37
|
+
-------
|
38
|
+
|
39
|
+
VerifiedDouble is still in its infancy, but I hope it's usable for the most common cases.
|
40
|
+
|
41
|
+
* If you check the RelishApp doc, the gem only supports a subset of rspec-mock's API. Please post an issue at http://github.com/gsmendoza/verified_double if you need support for any particular rspec-mock API.
|
42
|
+
|
43
|
+
* The [method documentation](http://rubydoc.info/gems/verified_double) is pretty empty at this point :p I'm planning to use yard-spec to document the methods but that gem doesn't support rspec context blocks. I'll try to work on that soon.
|
33
44
|
|
34
45
|
Special thanks
|
35
46
|
--------------
|
data/features/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
0.2.0 - 2013-06-30
|
2
|
+
------------------
|
3
|
+
|
4
|
+
* [#4] Add stack frames and relish app link to output.
|
5
|
+
* [#12] RecordingDouble#class should be the class of the object being doubled.
|
6
|
+
* [#16] Fix handling of doubles passed as method signature values.
|
7
|
+
|
8
|
+
Known issues:
|
9
|
+
|
10
|
+
* Stack frames sometimes point to verified_double gem instead of where the mock was recorded.
|
11
|
+
|
12
|
+
|
1
13
|
0.1.1 - 2013-06-26
|
2
14
|
------------------
|
3
15
|
|
data/features/readme.md
CHANGED
@@ -2,34 +2,45 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/gsmendoza/verified_double)
|
4
4
|
|
5
|
-
VerifiedDouble
|
5
|
+
VerifiedDouble is a gem for verifying rspec mocks. The gem works similar to [rspec-fire](https://github.com/xaviershay/rspec-fire). However, instead of checking if the doubled classes respond to the methods, the gem looks for tests confirming if those mocks are valid.
|
6
6
|
|
7
7
|
For example, let's say I mocked the created_at method of a model like this:
|
8
8
|
|
9
9
|
item = VerifiedDouble.of_instance(Item)
|
10
10
|
item.should_receive(:created_at).and_return(Time.now)
|
11
11
|
|
12
|
-
|
13
|
-
running the tests, the gem looks for a test that confirms if you can
|
14
|
-
indeed call #created_at on Item. The test should also ensure that the method
|
15
|
-
returns a Time object. Since this is hard to automate, the gem just looks
|
16
|
-
for a test with a tag saying it verifies that contract:
|
12
|
+
When running the tests, the gem looks for a "contract test" tagged with the method's signature. This test should ensure that calling #created_at on Item will return a Time object.
|
17
13
|
|
18
14
|
it "tests something", verifies_contract: 'Item#created_at()=>Time' do
|
19
15
|
#...
|
20
16
|
end
|
21
17
|
|
22
|
-
If this test does not exist, the gem will complain that the mock is not
|
23
|
-
verified.
|
18
|
+
If this test does not exist, the gem will complain that the mock is not verified.
|
24
19
|
|
25
|
-
|
20
|
+
I got the idea from http://www.infoq.com/presentations/integration-tests-scam, an old (2009) talk that still has some fresh insights on dealing with API changes in your mocked tests.
|
26
21
|
|
27
|
-
|
28
|
-
----------
|
22
|
+
You can learn more about using the gem at https://www.relishapp.com/gsmendoza/verified-double.
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
Actively tested against
|
25
|
+
-----------------------
|
26
|
+
|
27
|
+
* Ruby 1.9.3
|
28
|
+
* RSpec 2.13
|
29
|
+
|
30
|
+
|
31
|
+
Alternatives
|
32
|
+
------------
|
33
|
+
|
34
|
+
[Bogus](https://www.relishapp.com/bogus/bogus/v/0-0-3/docs/) is the first gem to implement contract tests. It doesn't rely on rspec tags to verify contracts, so it's probably a lot smarter than VerifiedDouble :) However, I wasn't able to try it out on my own projects because of its own rr-like mock adapter. But do check it out!
|
35
|
+
|
36
|
+
Caveats
|
37
|
+
-------
|
38
|
+
|
39
|
+
VerifiedDouble is still in its infancy, but I hope it's usable for the most common cases.
|
40
|
+
|
41
|
+
* If you check the RelishApp doc, the gem only supports a subset of rspec-mock's API. Please post an issue at http://github.com/gsmendoza/verified_double if you need support for any particular rspec-mock API.
|
42
|
+
|
43
|
+
* The [method documentation](http://rubydoc.info/gems/verified_double) is pretty empty at this point :p I'm planning to use yard-spec to document the methods but that gem doesn't support rspec context blocks. I'll try to work on that soon.
|
33
44
|
|
34
45
|
Special thanks
|
35
46
|
--------------
|
@@ -93,7 +93,8 @@ Feature: 01. Verified mocks
|
|
93
93
|
Then I should be informed that the mock is unverified:
|
94
94
|
"""
|
95
95
|
The following mocks are not verified:
|
96
|
-
|
96
|
+
|
97
|
+
1. Collaborator#some_method(SomeInput)=>SomeOutput
|
97
98
|
"""
|
98
99
|
|
99
100
|
Scenario: Verified class doubles
|
@@ -147,5 +148,6 @@ Feature: 01. Verified mocks
|
|
147
148
|
Then I should be informed that the mock is unverified:
|
148
149
|
"""
|
149
150
|
The following mocks are not verified:
|
150
|
-
|
151
|
+
|
152
|
+
1. Collaborator.some_method(SomeInput)=>SomeOutput
|
151
153
|
"""
|
data/lib/verified_double.rb
CHANGED
@@ -1,13 +1,22 @@
|
|
1
|
+
require 'active_support/core_ext/string'
|
1
2
|
require 'rspec/mocks'
|
2
3
|
|
3
4
|
require 'verified_double/boolean'
|
4
5
|
require 'verified_double/matchers'
|
5
6
|
require 'verified_double/method_signature'
|
6
|
-
require 'verified_double/
|
7
|
+
require 'verified_double/method_signature/value'
|
8
|
+
require 'verified_double/method_signature/instance_value'
|
9
|
+
require 'verified_double/method_signature/boolean_value'
|
10
|
+
require 'verified_double/method_signature/class_value'
|
11
|
+
require 'verified_double/method_signature/instance_double_value'
|
12
|
+
require 'verified_double/method_signature/recording_double_class_value'
|
13
|
+
require 'verified_double/method_signature/rspec_double_value'
|
7
14
|
require 'verified_double/method_signatures_report'
|
8
15
|
require 'verified_double/parse_method_signature'
|
16
|
+
require 'verified_double/recorded_method_signature'
|
9
17
|
require 'verified_double/recording_double'
|
10
18
|
require 'verified_double/relays_to_internal_double_returning_self'
|
19
|
+
require 'verified_double/stack_frame'
|
11
20
|
|
12
21
|
module VerifiedDouble
|
13
22
|
extend RSpec::Mocks::ExampleMethods
|
@@ -12,7 +12,7 @@ module VerifiedDouble
|
|
12
12
|
|
13
13
|
raise CannotHandleMultipleReturnValues if method_signature.return_values.size > 1
|
14
14
|
|
15
|
-
value = method_signature.return_values.first.
|
15
|
+
value = method_signature.return_values.first.content_as_instance
|
16
16
|
actual.send "#{method_signature.method}=", value
|
17
17
|
actual.send(method_signature.method) == value
|
18
18
|
end
|
@@ -26,7 +26,7 @@ module VerifiedDouble
|
|
26
26
|
|
27
27
|
raise CannotHandleMultipleReturnValues if method_signature.return_values.size > 1
|
28
28
|
|
29
|
-
actual.send(method_signature.method).is_a?(method_signature.return_values.first.
|
29
|
+
actual.send(method_signature.method).is_a?(method_signature.return_values.first.content)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -8,14 +8,14 @@ module VerifiedDouble
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
11
|
+
def belongs_to?(other)
|
12
12
|
self.class_name == other.class_name &&
|
13
13
|
self.method_operator == other.method_operator &&
|
14
14
|
self.method == other.method &&
|
15
15
|
self.args.size == other.args.size &&
|
16
|
-
(0 ... args.size).all?{|i| self.args[i].
|
16
|
+
(0 ... args.size).all?{|i| self.args[i].belongs_to?(other.args[i]) } &&
|
17
17
|
self.return_values.size == other.return_values.size &&
|
18
|
-
(0 ... return_values.size).all?{|i| self.return_values[i].
|
18
|
+
(0 ... return_values.size).all?{|i| self.return_values[i].belongs_to?(other.return_values[i]) }
|
19
19
|
end
|
20
20
|
|
21
21
|
def args
|
@@ -42,8 +42,8 @@ module VerifiedDouble
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def to_s
|
45
|
-
args_string = args.map(&:
|
46
|
-
return_values_string = return_values.map(&:
|
45
|
+
args_string = args.map(&:content).map{|v| v || 'nil'}.join(', ')
|
46
|
+
return_values_string = return_values.map(&:content).map{|v| v || 'nil'}.join(', ')
|
47
47
|
return_values_string = nil if return_values_string.empty?
|
48
48
|
|
49
49
|
result = [
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module VerifiedDouble
|
2
|
+
class MethodSignature
|
3
|
+
class ClassValue < Value
|
4
|
+
def belongs_to?(other)
|
5
|
+
self.content == other.content
|
6
|
+
end
|
7
|
+
|
8
|
+
def content_as_instance
|
9
|
+
begin
|
10
|
+
content.new
|
11
|
+
rescue NoMethodError
|
12
|
+
Object.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module VerifiedDouble
|
2
|
+
class MethodSignature
|
3
|
+
class InstanceValue < Value
|
4
|
+
def belongs_to?(other)
|
5
|
+
if other.is_a?(MethodSignature::InstanceValue)
|
6
|
+
self.content == other.content
|
7
|
+
else
|
8
|
+
self.content_class.ancestors.include?(other.content)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def content_as_instance
|
13
|
+
self.content
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module VerifiedDouble
|
2
|
+
class MethodSignature
|
3
|
+
class Value
|
4
|
+
attr_reader :content
|
5
|
+
|
6
|
+
def self.from(content)
|
7
|
+
if content == true || content == false
|
8
|
+
BooleanValue.new(content)
|
9
|
+
elsif content.is_a?(RSpec::Mocks::Mock)
|
10
|
+
RspecDoubleValue.new(content)
|
11
|
+
elsif content.respond_to?(:doubled_class)
|
12
|
+
if content.class_double?
|
13
|
+
RecordingDoubleClassValue.new(content)
|
14
|
+
else
|
15
|
+
InstanceDoubleValue.new(content)
|
16
|
+
end
|
17
|
+
elsif content.is_a?(Module)
|
18
|
+
ClassValue.new(content)
|
19
|
+
else
|
20
|
+
InstanceValue.new(content)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(content)
|
25
|
+
@content = content
|
26
|
+
end
|
27
|
+
|
28
|
+
def content_class
|
29
|
+
content.class
|
30
|
+
end
|
31
|
+
|
32
|
+
def recommended_value
|
33
|
+
MethodSignature::Value.from(self.content_class)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -14,7 +14,7 @@ module VerifiedDouble
|
|
14
14
|
def identify_unverified_signatures
|
15
15
|
@unverified_signatures = @registered_signatures.select{|registered_signature|
|
16
16
|
@verified_signatures.all?{|verified_signature|
|
17
|
-
! registered_signature.
|
17
|
+
! registered_signature.belongs_to?(verified_signature) } }
|
18
18
|
self
|
19
19
|
end
|
20
20
|
|
@@ -25,8 +25,15 @@ module VerifiedDouble
|
|
25
25
|
|
26
26
|
def output_unverified_signatures
|
27
27
|
if @unverified_signatures.any?
|
28
|
-
output = ["The following mocks are not verified:" ] +
|
29
|
-
|
28
|
+
output = [nil, "The following mocks are not verified:" ] +
|
29
|
+
@unverified_signatures
|
30
|
+
.map(&:recommended_verified_signature)
|
31
|
+
.map(&:to_s)
|
32
|
+
.sort
|
33
|
+
.each_with_index
|
34
|
+
.map{|string, i| "#{i+1}. #{string}" } +
|
35
|
+
["For more info, check out https://www.relishapp.com/gsmendoza/verified-double."]
|
36
|
+
puts output.join("\n\n")
|
30
37
|
end
|
31
38
|
self
|
32
39
|
end
|
@@ -9,7 +9,7 @@ module VerifiedDouble
|
|
9
9
|
def args
|
10
10
|
results = string.scan(/\((.*)\)/)[0]
|
11
11
|
if results
|
12
|
-
results[0].split(',').map{|arg|
|
12
|
+
results[0].split(',').map{|arg| MethodSignature::Value.from(eval(arg)) }
|
13
13
|
else
|
14
14
|
[]
|
15
15
|
end
|
@@ -40,7 +40,7 @@ module VerifiedDouble
|
|
40
40
|
results = string.scan(/=>(.*)/)[0]
|
41
41
|
if results
|
42
42
|
results[0].split(',').map{|return_value|
|
43
|
-
|
43
|
+
MethodSignature::Value.from(eval(return_value)) }
|
44
44
|
else
|
45
45
|
[]
|
46
46
|
end
|
@@ -21,11 +21,15 @@ module VerifiedDouble
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def and_return(return_value)
|
24
|
-
self.method_signatures.last.return_values = [
|
24
|
+
self.method_signatures.last.return_values = [MethodSignature::Value.from(return_value)]
|
25
25
|
@double_call.and_return(return_value)
|
26
26
|
self
|
27
27
|
end
|
28
28
|
|
29
|
+
def class
|
30
|
+
class_double? ? Class : doubled_class
|
31
|
+
end
|
32
|
+
|
29
33
|
def class_double?
|
30
34
|
! double.is_a?(RSpec::Mocks::Mock)
|
31
35
|
end
|
@@ -34,6 +38,10 @@ module VerifiedDouble
|
|
34
38
|
__getobj__
|
35
39
|
end
|
36
40
|
|
41
|
+
def doubled_class
|
42
|
+
class_name.constantize
|
43
|
+
end
|
44
|
+
|
37
45
|
def inspect
|
38
46
|
to_s
|
39
47
|
end
|
@@ -64,7 +72,7 @@ module VerifiedDouble
|
|
64
72
|
|
65
73
|
def with(*args)
|
66
74
|
self.method_signatures.last.args =
|
67
|
-
args.map{|arg|
|
75
|
+
args.map{|arg| MethodSignature::Value.from(arg) }
|
68
76
|
@double_call.with(*args)
|
69
77
|
self
|
70
78
|
end
|
@@ -72,10 +80,11 @@ module VerifiedDouble
|
|
72
80
|
private
|
73
81
|
|
74
82
|
def add_method_signature(method)
|
75
|
-
method_signature =
|
83
|
+
method_signature = RecordedMethodSignature.new(
|
76
84
|
class_name: class_name,
|
77
85
|
method_operator: method_operator,
|
78
|
-
method: method.to_s
|
86
|
+
method: method.to_s,
|
87
|
+
stack_frame: StackFrame.new(caller(2)[0]))
|
79
88
|
|
80
89
|
self.method_signatures << method_signature
|
81
90
|
end
|