stendhal 0.1.4 → 0.1.5
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/Gemfile.lock +1 -1
- data/Readme.md +29 -2
- data/features/mocks.feature +71 -0
- data/lib/stendhal/core_ext/object.rb +3 -0
- data/lib/stendhal/example.rb +2 -0
- data/lib/stendhal/mocks/mock_verifier.rb +71 -0
- data/lib/stendhal/mocks/mockable.rb +34 -0
- data/lib/stendhal/mocks.rb +2 -0
- data/lib/stendhal/version.rb +1 -1
- data/lib/stendhal.rb +1 -0
- data/spec/stendhal/example_spec.rb +20 -0
- data/spec/stendhal/mocks/mock_verifier_spec.rb +138 -0
- data/spec/stendhal/mocks/mockable_spec.rb +26 -0
- data/spec/stendhal/{test_double_spec.rb → mocks/test_double_spec.rb} +0 -0
- metadata +14 -5
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
@@ -10,9 +10,9 @@ development.
|
|
10
10
|
|
11
11
|
* Pretty decent reporter with colors
|
12
12
|
* Test doubles and stubs (no partial stubbing yet)
|
13
|
+
* Mocks (message expectations)
|
13
14
|
* Nested example groups (declare them with either describe or context)
|
14
15
|
* Pending examples
|
15
|
-
* Lame reporter (but will get better eventually)
|
16
16
|
* Matchers (use with object.must or object.must_not)
|
17
17
|
|
18
18
|
eq() / eql()
|
@@ -86,6 +86,22 @@ development.
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
describe "Message expectation" do
|
90
|
+
it "is declared with expects" do
|
91
|
+
string = "my string"
|
92
|
+
string.expects(:reverse)
|
93
|
+
|
94
|
+
string.reverse # Expectation fulfilled!
|
95
|
+
end
|
96
|
+
|
97
|
+
it "is declared with does_not_expect in case it is negative" do
|
98
|
+
string = "my string"
|
99
|
+
string.does_not_expect(:reverse)
|
100
|
+
|
101
|
+
string.reverse # Fails!
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
89
105
|
end
|
90
106
|
|
91
107
|
###Running the specs!
|
@@ -114,7 +130,18 @@ development.
|
|
114
130
|
* is declared with double as well
|
115
131
|
* can be given stubs
|
116
132
|
|
117
|
-
|
133
|
+
Message expectation
|
134
|
+
* is declared with expects
|
135
|
+
* is declared with does_not_expect in case it is negative
|
136
|
+
|
137
|
+
13 examples, 3 failures, 2 pending
|
138
|
+
|
139
|
+
##Feedback
|
140
|
+
|
141
|
+
Reporting issues, asking for new features and constructive criticizing can be
|
142
|
+
done either through Github issues, the mailing list
|
143
|
+
(http://librelist.com/browser/stendhal/) or you can always reach me on twitter
|
144
|
+
(I am @txustice). Don't hesitate to tell me anything! :)
|
118
145
|
|
119
146
|
##Note on Patches/Pull Requests
|
120
147
|
|
@@ -0,0 +1,71 @@
|
|
1
|
+
Feature: Mocks (message expectations)
|
2
|
+
|
3
|
+
With mocks you can check whether objects receive certain messages.
|
4
|
+
|
5
|
+
Scenario: declare a message expectation
|
6
|
+
Given a directory named "stendhal_project"
|
7
|
+
When I cd to "stendhal_project"
|
8
|
+
Given a file named "sample_spec.rb" with:
|
9
|
+
"""
|
10
|
+
class MyClass
|
11
|
+
|
12
|
+
def foo
|
13
|
+
end
|
14
|
+
|
15
|
+
def bar
|
16
|
+
foo
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "bar" do
|
22
|
+
it "calls foo" do
|
23
|
+
object = MyClass.new
|
24
|
+
object.expects(:foo)
|
25
|
+
|
26
|
+
object.bar
|
27
|
+
end
|
28
|
+
it "never calls foo" do
|
29
|
+
object = MyClass.new
|
30
|
+
object.expects(:foo)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
"""
|
34
|
+
When I run "stendhal sample_spec.rb"
|
35
|
+
Then the exit status should be 0
|
36
|
+
And the output should contain "2 examples, 1 failure"
|
37
|
+
And the output should contain "expected to be sent :foo 1 time, but received it 0 times"
|
38
|
+
|
39
|
+
Scenario: declare a negative message expectation
|
40
|
+
Given a directory named "stendhal_project"
|
41
|
+
When I cd to "stendhal_project"
|
42
|
+
Given a file named "sample_spec.rb" with:
|
43
|
+
"""
|
44
|
+
class MyClass
|
45
|
+
|
46
|
+
def foo
|
47
|
+
end
|
48
|
+
|
49
|
+
def bar
|
50
|
+
foo
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "bar" do
|
56
|
+
it "calls foo" do
|
57
|
+
object = MyClass.new
|
58
|
+
object.does_not_expect(:foo)
|
59
|
+
|
60
|
+
object.bar
|
61
|
+
end
|
62
|
+
it "never calls foo" do
|
63
|
+
object = MyClass.new
|
64
|
+
object.does_not_expect(:foo)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
"""
|
68
|
+
When I run "stendhal sample_spec.rb"
|
69
|
+
Then the exit status should be 0
|
70
|
+
And the output should contain "2 examples, 1 failure"
|
71
|
+
And the output should contain "expected to be sent :foo 0 times, but received it 1 time"
|
data/lib/stendhal/example.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Stendhal
|
2
|
+
module Mocks
|
3
|
+
class MockVerifier
|
4
|
+
|
5
|
+
@@verifiers = []
|
6
|
+
|
7
|
+
attr_reader :expectations
|
8
|
+
|
9
|
+
def initialize(object)
|
10
|
+
@expectations = []
|
11
|
+
@object = object
|
12
|
+
@@verifiers << self
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_expectation(method)
|
16
|
+
@expectations << MessageExpectation.new(method)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_negative_expectation(method)
|
20
|
+
@expectations << MessageExpectation.new(method, :negative => true)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fulfill_expectation(method)
|
24
|
+
@expectations.select{|e| e.method == method}.each(&:register_call)
|
25
|
+
end
|
26
|
+
|
27
|
+
def verify!
|
28
|
+
expectations.each do |expectation|
|
29
|
+
begin
|
30
|
+
expectation.verify
|
31
|
+
rescue Stendhal::Exceptions::ExpectationNotMet=>e
|
32
|
+
raise Stendhal::Exceptions::ExpectationNotMet.new "#{@object} #{e.message}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.verifiers
|
38
|
+
@@verifiers
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.verify!
|
42
|
+
verifiers.each(&:verify!)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.reset!
|
46
|
+
@@verifiers = []
|
47
|
+
end
|
48
|
+
|
49
|
+
class MessageExpectation
|
50
|
+
attr_reader :method
|
51
|
+
attr_reader :times_called
|
52
|
+
attr_reader :times_expected
|
53
|
+
|
54
|
+
def initialize(method, options = {})
|
55
|
+
@method = method
|
56
|
+
@times_expected = options[:negative] ? 0 : 1
|
57
|
+
@times_called = 0
|
58
|
+
end
|
59
|
+
|
60
|
+
def register_call
|
61
|
+
@times_called += 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def verify
|
65
|
+
raise Stendhal::Exceptions::ExpectationNotMet.new "expected to be sent :#{method} #{times_expected} time#{times_expected == 1 ? '' : 's'}, but received it #{times_called} time#{times_called == 1 ? '' : 's'}" unless times_expected == times_called
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Stendhal
|
2
|
+
module Mocks
|
3
|
+
module Mockable
|
4
|
+
|
5
|
+
def expects(method, options = {})
|
6
|
+
if options[:negative]
|
7
|
+
__verifier.add_negative_expectation(method)
|
8
|
+
else
|
9
|
+
__verifier.add_expectation(method)
|
10
|
+
end
|
11
|
+
metaclass = (class << self;self;end)
|
12
|
+
metaclass.send(:alias_method, :"__original_#{method}", method.to_sym)
|
13
|
+
metaclass.send(:undef_method, method.to_sym)
|
14
|
+
metaclass.class_eval <<EOT
|
15
|
+
def #{method}(*args, &block)
|
16
|
+
@__verifier.fulfill_expectation(:#{method},*args,&block)
|
17
|
+
__original_#{method}(*args,&block)
|
18
|
+
end
|
19
|
+
EOT
|
20
|
+
end
|
21
|
+
|
22
|
+
def does_not_expect(method)
|
23
|
+
expects(method, :negative => true)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def __verifier
|
29
|
+
@__verifier ||= MockVerifier.new(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/stendhal/mocks.rb
CHANGED
data/lib/stendhal/version.rb
CHANGED
data/lib/stendhal.rb
CHANGED
@@ -60,6 +60,26 @@ module Stendhal
|
|
60
60
|
example.should be_aborted
|
61
61
|
end
|
62
62
|
|
63
|
+
it "verifies all message expectations after running the block" do
|
64
|
+
example = Example.new("docstring") do
|
65
|
+
|
66
|
+
end
|
67
|
+
example.should_receive(:instance_eval).ordered
|
68
|
+
Stendhal::Mocks::MockVerifier.should_receive(:verify!).ordered
|
69
|
+
|
70
|
+
example.run
|
71
|
+
end
|
72
|
+
|
73
|
+
it "resets all message expectations before running the block" do
|
74
|
+
example = Example.new("docstring") do
|
75
|
+
|
76
|
+
end
|
77
|
+
Stendhal::Mocks::MockVerifier.should_receive(:reset!)
|
78
|
+
example.should_receive(:instance_eval).ordered
|
79
|
+
|
80
|
+
example.run
|
81
|
+
end
|
82
|
+
|
63
83
|
end
|
64
84
|
|
65
85
|
describe "#fail" do
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Stendhal
|
4
|
+
module Mocks
|
5
|
+
describe MockVerifier do
|
6
|
+
|
7
|
+
subject { verifier = MockVerifier.new('object') }
|
8
|
+
|
9
|
+
it 'includes itself in verifiers when created' do
|
10
|
+
subject
|
11
|
+
MockVerifier.should have(1).verifiers
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "instance methods" do
|
15
|
+
|
16
|
+
describe "#add_expectation" do
|
17
|
+
it 'adds an expectation for a given method' do
|
18
|
+
MockVerifier::MessageExpectation.should_receive(:new).with(:reverse)
|
19
|
+
|
20
|
+
subject.add_expectation(:reverse)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#add_negative_expectation" do
|
25
|
+
it 'adds a negative expectation for a given method' do
|
26
|
+
MockVerifier::MessageExpectation.should_receive(:new).with(:reverse, :negative => true)
|
27
|
+
|
28
|
+
subject.add_negative_expectation(:reverse)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#fulfill_expectation" do
|
33
|
+
it 'registers a call for a given method' do
|
34
|
+
subject.add_expectation(:reverse)
|
35
|
+
subject.expectations.first.should_receive(:register_call)
|
36
|
+
|
37
|
+
subject.fulfill_expectation(:reverse)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#verify!" do
|
42
|
+
it 'verifies each of the expectations until one fails' do
|
43
|
+
expectations = [double, double, double]
|
44
|
+
expectations.each do |e|
|
45
|
+
e.should_receive(:verify)
|
46
|
+
end
|
47
|
+
subject.should_receive(:expectations).and_return(expectations)
|
48
|
+
|
49
|
+
subject.verify!
|
50
|
+
end
|
51
|
+
it 'adds the object inspect to the message if raised any ExpectationNotMet' do
|
52
|
+
expectations = [double, double, double]
|
53
|
+
expectations.first.should_receive(:verify).and_raise(Stendhal::Exceptions::ExpectationNotMet.new('expected foo to be bar'))
|
54
|
+
|
55
|
+
subject.should_receive(:expectations).and_return(expectations)
|
56
|
+
|
57
|
+
expect {
|
58
|
+
subject.verify!
|
59
|
+
}.to raise_error(Stendhal::Exceptions::ExpectationNotMet, "object expected foo to be bar")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "class methods" do
|
66
|
+
|
67
|
+
describe "#verify!" do
|
68
|
+
it 'verifies each of the verifiers' do
|
69
|
+
verifiers = [double, double, double]
|
70
|
+
verifiers.each { |v| v.should_receive(:verify!) }
|
71
|
+
MockVerifier.should_receive(:verifiers).and_return verifiers
|
72
|
+
|
73
|
+
MockVerifier.verify!
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#reset!" do
|
78
|
+
it 'deletes all verifiers' do
|
79
|
+
MockVerifier.new('object')
|
80
|
+
MockVerifier.new('other object')
|
81
|
+
|
82
|
+
MockVerifier.reset!
|
83
|
+
|
84
|
+
MockVerifier.should have(0).verifiers
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
describe MockVerifier::MessageExpectation do
|
93
|
+
|
94
|
+
subject { MockVerifier::MessageExpectation.new(:length) }
|
95
|
+
|
96
|
+
it "initializes with 0 times called" do
|
97
|
+
subject.times_called.should == 0
|
98
|
+
end
|
99
|
+
|
100
|
+
context "when given no options" do
|
101
|
+
it "initializes with 1 times expected" do
|
102
|
+
subject.times_expected.should == 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when given :negative => true" do
|
107
|
+
it "initializes with 0 times expected" do
|
108
|
+
negative_expectation = MockVerifier::MessageExpectation.new(:length, :negative => true)
|
109
|
+
negative_expectation.times_expected.should == 0
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "instance methods" do
|
114
|
+
|
115
|
+
describe "#register_call" do
|
116
|
+
it 'registers a call for the given expectation' do
|
117
|
+
expect{
|
118
|
+
subject.register_call
|
119
|
+
}.to change(subject, :times_called).by(1)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "#verify" do
|
124
|
+
it 'registers a call for the given expectation' do
|
125
|
+
subject.stub(:times_called).and_return 2
|
126
|
+
subject.stub(:times_expected).and_return 1
|
127
|
+
|
128
|
+
expect {
|
129
|
+
subject.verify
|
130
|
+
}.to raise_error(Stendhal::Exceptions::ExpectationNotMet, "expected to be sent :length 1 time, but received it 2 times")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class MyArray < Array
|
4
|
+
include Stendhal::Mocks::Mockable
|
5
|
+
end
|
6
|
+
|
7
|
+
module Stendhal
|
8
|
+
module Mocks
|
9
|
+
describe "a Mockable class" do
|
10
|
+
|
11
|
+
subject { MyArray.new([1,2,3]) }
|
12
|
+
|
13
|
+
describe "#expects" do
|
14
|
+
it 'creates a verifier' do
|
15
|
+
subject.expects(:length)
|
16
|
+
subject.send(:__verifier).should be_a(MockVerifier)
|
17
|
+
end
|
18
|
+
it 'creates a message expectation on the given method' do
|
19
|
+
subject.expects(:length)
|
20
|
+
subject.send(:__verifier).expectations.map(&:method).should include(:length)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
File without changes
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 5
|
9
|
+
version: 0.1.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Josep M. Bach
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-11-
|
17
|
+
date: 2010-11-09 00:00:00 +01:00
|
18
18
|
default_executable: stendhal
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -91,12 +91,14 @@ files:
|
|
91
91
|
- bin/stendhal
|
92
92
|
- features/examples.feature
|
93
93
|
- features/expectations.feature
|
94
|
+
- features/mocks.feature
|
94
95
|
- features/reporter.feature
|
95
96
|
- features/support/env.rb
|
96
97
|
- features/test_doubles_and_stubs.feature
|
97
98
|
- lib/stendhal.rb
|
98
99
|
- lib/stendhal/autorun.rb
|
99
100
|
- lib/stendhal/core_ext/kernel.rb
|
101
|
+
- lib/stendhal/core_ext/object.rb
|
100
102
|
- lib/stendhal/dsl.rb
|
101
103
|
- lib/stendhal/example.rb
|
102
104
|
- lib/stendhal/example_group.rb
|
@@ -107,6 +109,8 @@ files:
|
|
107
109
|
- lib/stendhal/matchers/kind.rb
|
108
110
|
- lib/stendhal/matchers/predicate.rb
|
109
111
|
- lib/stendhal/mocks.rb
|
112
|
+
- lib/stendhal/mocks/mock_verifier.rb
|
113
|
+
- lib/stendhal/mocks/mockable.rb
|
110
114
|
- lib/stendhal/mocks/test_double.rb
|
111
115
|
- lib/stendhal/reporter.rb
|
112
116
|
- lib/stendhal/version.rb
|
@@ -120,8 +124,10 @@ files:
|
|
120
124
|
- spec/stendhal/matchers/kind_spec.rb
|
121
125
|
- spec/stendhal/matchers/predicate_spec.rb
|
122
126
|
- spec/stendhal/matchers_spec.rb
|
127
|
+
- spec/stendhal/mocks/mock_verifier_spec.rb
|
128
|
+
- spec/stendhal/mocks/mockable_spec.rb
|
129
|
+
- spec/stendhal/mocks/test_double_spec.rb
|
123
130
|
- spec/stendhal/reporter_spec.rb
|
124
|
-
- spec/stendhal/test_double_spec.rb
|
125
131
|
- stendhal.gemspec
|
126
132
|
has_rdoc: true
|
127
133
|
homepage: http://rubygems.org/gems/stendhal
|
@@ -158,6 +164,7 @@ summary: Stendhal is a really simple test framework.
|
|
158
164
|
test_files:
|
159
165
|
- features/examples.feature
|
160
166
|
- features/expectations.feature
|
167
|
+
- features/mocks.feature
|
161
168
|
- features/reporter.feature
|
162
169
|
- features/support/env.rb
|
163
170
|
- features/test_doubles_and_stubs.feature
|
@@ -170,5 +177,7 @@ test_files:
|
|
170
177
|
- spec/stendhal/matchers/kind_spec.rb
|
171
178
|
- spec/stendhal/matchers/predicate_spec.rb
|
172
179
|
- spec/stendhal/matchers_spec.rb
|
180
|
+
- spec/stendhal/mocks/mock_verifier_spec.rb
|
181
|
+
- spec/stendhal/mocks/mockable_spec.rb
|
182
|
+
- spec/stendhal/mocks/test_double_spec.rb
|
173
183
|
- spec/stendhal/reporter_spec.rb
|
174
|
-
- spec/stendhal/test_double_spec.rb
|