stubborn 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|