stubborn 0.1.2 → 0.1.3
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 +29 -11
- data/VERSION +1 -1
- data/lib/missed_stub_exception.rb +3 -3
- data/lib/stubborn.rb +11 -9
- data/stubborn.gemspec +2 -2
- data/test/stubborn_test.rb +30 -0
- data/test/suggesters/rspec_suggester_test.rb +6 -2
- metadata +1 -1
data/README.rdoc
CHANGED
@@ -2,11 +2,15 @@
|
|
2
2
|
|
3
3
|
A Ruby gem that helps you find missing stubs in your tests.
|
4
4
|
|
5
|
-
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
Let's explain through an example. Say you have this classes:
|
6
8
|
|
7
9
|
class Api
|
8
10
|
def slow_method(a, b, c)
|
9
11
|
...
|
12
|
+
#this is slow or dangerous, so you want to stub it in your tests
|
13
|
+
...
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
@@ -18,33 +22,47 @@ Say you have this classes:
|
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
21
|
-
And you
|
25
|
+
And you've forgot to stub your api class in many tests of your huge test suite:
|
26
|
+
|
27
|
+
it "should do something useful" do
|
28
|
+
MyClassThatUsesApi.new.useful_method.should be_useful
|
29
|
+
end
|
30
|
+
|
31
|
+
Then you could use stubborn to help you find and prevent those misses just by adding this somewhere in your test_helper/spec_helper:
|
22
32
|
|
23
33
|
require 'rubygems'
|
24
34
|
require 'stubborn'
|
25
35
|
|
26
36
|
Stubborn.should_be_stubbed(Api)
|
27
|
-
|
28
|
-
Then if you forget about stubbing the api class in some of your tests like this:
|
29
|
-
|
30
|
-
it "should do something useful" do
|
31
|
-
MyClassThatUsesApi.new.useful_method.should be_useful
|
32
|
-
end
|
33
37
|
|
34
|
-
|
38
|
+
Now each test with a missing stub will fail throwing an exception that includes all information you need to construct the correct stub:
|
35
39
|
|
36
40
|
You've missed adding a stub. Consider this suggestions:
|
37
41
|
api_instance.stub!(:slow_method).with(123, AClass, "hi").and_return(another_class_instance)
|
38
42
|
api_instance.stub!(:slow_method).and_return(another_class_instance)
|
39
43
|
|
44
|
+
You have some control on the output by using the :label option so you can better match the way you usually call the methods from your test:
|
45
|
+
|
46
|
+
Stubborn.should_be_stubbed(Api, :label => "GreatClass.singleton")
|
47
|
+
|
48
|
+
Which produces this output:
|
49
|
+
|
50
|
+
You've missed adding a stub. Consider this suggestions:
|
51
|
+
GreatClass.singleton.stub!(:slow_method).with(123, AClass, "hi").and_return(another_class_instance)
|
52
|
+
GreatClass.singleton.stub!(:slow_method).and_return(another_class_instance)
|
53
|
+
|
54
|
+
So all class methods of the Api class and all its instances will raise this special exception while running the tests. If you prefer you can use it on a single instance like this:
|
55
|
+
|
56
|
+
Stubborn.should_be_stubbed(Api.new)
|
57
|
+
|
40
58
|
== Installation
|
41
59
|
|
42
|
-
sudo gem install stubborn
|
60
|
+
sudo gem install stubborn -s http://gemcutter.org
|
43
61
|
|
44
62
|
== To Do
|
45
63
|
|
46
64
|
* Filters so that you can choose which methods to include or exclude
|
47
|
-
*
|
65
|
+
* Give stub suggestions for more test frameworks. It currently shows only rspec syntax
|
48
66
|
|
49
67
|
== Collaborate
|
50
68
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Stubborn
|
2
2
|
class MissedStubException < RuntimeError
|
3
|
-
def initialize(
|
4
|
-
object_label = friendly_name(
|
3
|
+
def initialize(object_or_label, method_name, args, result, suggester)
|
4
|
+
object_label = object_or_label.respond_to?(:to_str) ? object_or_label : friendly_name(object_or_label)
|
5
5
|
args = args.map{|a| friendly_name(a)}.join(", ")
|
6
6
|
result = friendly_name(result)
|
7
7
|
|
@@ -15,7 +15,7 @@ module Stubborn
|
|
15
15
|
private
|
16
16
|
def friendly_name(object)
|
17
17
|
return "\"#{object}\"" if object.respond_to?(:to_str)
|
18
|
-
return object.inspect if object.respond_to?(:to_int)
|
18
|
+
return object.inspect if object.respond_to?(:to_int) || object.is_a?(Hash)
|
19
19
|
|
20
20
|
if object.is_a?(Class)
|
21
21
|
object.name
|
data/lib/stubborn.rb
CHANGED
@@ -9,11 +9,11 @@ require 'suggesters/rspec_suggester'
|
|
9
9
|
require 'missed_stub_exception'
|
10
10
|
|
11
11
|
module Stubborn
|
12
|
-
def self.should_be_stubbed(object)
|
12
|
+
def self.should_be_stubbed(object, options = {})
|
13
13
|
if object.is_a?(Class)
|
14
|
-
ProxyForClass.new(object)
|
14
|
+
ProxyForClass.new(object, options)
|
15
15
|
else
|
16
|
-
ProxyForInstance.new(object)
|
16
|
+
ProxyForInstance.new(object, options)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -21,10 +21,12 @@ module Stubborn
|
|
21
21
|
attr_accessor :proxy_target
|
22
22
|
proxy_to :proxy_target, :blank_slate => true
|
23
23
|
|
24
|
-
def initialize(proxy_target,
|
24
|
+
def initialize(proxy_target, options = {})
|
25
|
+
options = {:class => proxy_target.class}.merge(options)
|
26
|
+
@label = options[:label]
|
25
27
|
@proxy_target = proxy_target
|
26
|
-
@klass =
|
27
|
-
@methods_to_skip = ["respond_to?", "is_a?"]
|
28
|
+
@klass = options[:class]
|
29
|
+
@methods_to_skip = ["respond_to?", "is_a?", "kind_of?", "equal?", "eql?", "==", "==="]
|
28
30
|
end
|
29
31
|
|
30
32
|
def class
|
@@ -34,12 +36,12 @@ module Stubborn
|
|
34
36
|
def method_missing(method_name, *args, &block)
|
35
37
|
result = @proxy_target.send(method_name, *args, &block)
|
36
38
|
return result if @methods_to_skip.include?(method_name.to_s)
|
37
|
-
raise MissedStubException.new(@proxy_target, method_name, args, result, Suggesters::RSpecSuggester)
|
39
|
+
raise MissedStubException.new(@label || @proxy_target, method_name, args, result, Suggesters::RSpecSuggester)
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
43
|
class ProxyForClass < ProxyForInstance
|
42
|
-
def initialize(proxy_target)
|
44
|
+
def initialize(proxy_target, options = {})
|
43
45
|
super
|
44
46
|
redefine_const(proxy_target.name, self) unless proxy_target.name.strip.empty?
|
45
47
|
end
|
@@ -50,7 +52,7 @@ module Stubborn
|
|
50
52
|
|
51
53
|
def new(*args, &block)
|
52
54
|
new_instance = @proxy_target.new(*args, &block)
|
53
|
-
ProxyForInstance.new(new_instance, self)
|
55
|
+
ProxyForInstance.new(new_instance, :class => self)
|
54
56
|
end
|
55
57
|
|
56
58
|
private
|
data/stubborn.gemspec
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{stubborn}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.3"
|
6
|
+
|
6
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
7
8
|
s.authors = ["Daniel Cadenas"]
|
8
9
|
s.date = %q{2009-10-02}
|
@@ -11,7 +12,6 @@ Gem::Specification.new do |s|
|
|
11
12
|
"LICENSE",
|
12
13
|
"README.rdoc"
|
13
14
|
]
|
14
|
-
|
15
15
|
s.files = [
|
16
16
|
".document",
|
17
17
|
".gitignore",
|
data/test/stubborn_test.rb
CHANGED
@@ -28,6 +28,24 @@ Expectations do
|
|
28
28
|
api.class.name
|
29
29
|
end
|
30
30
|
|
31
|
+
%w[is_a? kind_of?].each do |method|
|
32
|
+
expect true do
|
33
|
+
reset_test_api_class
|
34
|
+
api = TestApi.new
|
35
|
+
api = Stubborn.should_be_stubbed(api)
|
36
|
+
api.__send__(method, TestApi)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
%w[equal? eql? == ===].each do |method|
|
41
|
+
expect true do
|
42
|
+
reset_test_api_class
|
43
|
+
api = TestApi.new
|
44
|
+
proxied_api = Stubborn.should_be_stubbed(api)
|
45
|
+
proxied_api.__send__(method, api)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
31
49
|
expect true do
|
32
50
|
reset_test_api_class
|
33
51
|
api = TestApi.new
|
@@ -61,6 +79,18 @@ Expectations do
|
|
61
79
|
end
|
62
80
|
end
|
63
81
|
|
82
|
+
expect "You've missed adding a stub. Consider this suggestions:\nApi.singleton.stub!(:plus_one).with(0).and_return(1)\nApi.singleton.stub!(:plus_one).and_return(1)" do
|
83
|
+
reset_test_api_class
|
84
|
+
api = TestApi.new
|
85
|
+
api = Stubborn.should_be_stubbed(api, :label => "Api.singleton")
|
86
|
+
message = ""
|
87
|
+
begin
|
88
|
+
api.plus_one(0)
|
89
|
+
rescue => e
|
90
|
+
message = e.message
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
64
94
|
expect "TestApi" do
|
65
95
|
reset_test_api_class
|
66
96
|
Stubborn.should_be_stubbed(TestApi)
|
@@ -6,12 +6,16 @@ class Api; end
|
|
6
6
|
include Stubborn
|
7
7
|
|
8
8
|
Expectations do
|
9
|
-
expect "You've missed adding a stub. Consider this suggestions:\napi_instance.stub!(:method).with(123, AClass, \"hi\").and_return(aclass_instance)\napi_instance.stub!(:method).and_return(aclass_instance)" do
|
10
|
-
MissedStubException.new(Api.new, :method, [123, AClass,"hi"], AClass.new, Suggesters::RSpecSuggester).message
|
9
|
+
expect "You've missed adding a stub. Consider this suggestions:\napi_instance.stub!(:method).with(123, AClass, \"hi\", {1=>2}).and_return(aclass_instance)\napi_instance.stub!(:method).and_return(aclass_instance)" do
|
10
|
+
MissedStubException.new(Api.new, :method, [123, AClass,"hi", {1 => 2}], AClass.new, Suggesters::RSpecSuggester).message
|
11
11
|
end
|
12
12
|
|
13
13
|
expect "You've missed adding a stub. Consider this suggestion:\napi_instance.stub!(:method).and_return(aclass_instance)" do
|
14
14
|
MissedStubException.new(Api.new, :method, [], AClass.new, Suggesters::RSpecSuggester).message
|
15
15
|
end
|
16
|
+
|
17
|
+
expect "You've missed adding a stub. Consider this suggestion:\nApi.singleton.stub!(:method).and_return(aclass_instance)" do
|
18
|
+
MissedStubException.new("Api.singleton", :method, [], AClass.new, Suggesters::RSpecSuggester).message
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|