stendhal 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stendhal (0.1.3)
4
+ stendhal (0.1.4)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
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
- 11 examples, 2 failures, 2 pending
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"
@@ -0,0 +1,3 @@
1
+ class Object
2
+ include Stendhal::Mocks::Mockable
3
+ end
@@ -19,7 +19,9 @@ module Stendhal
19
19
 
20
20
  def run
21
21
  begin
22
+ Stendhal::Mocks::MockVerifier.reset!
22
23
  self.instance_eval(&@block)
24
+ Stendhal::Mocks::MockVerifier.verify!
23
25
  return 0
24
26
  rescue Exceptions::ExpectationNotMet=>e
25
27
  @failed = true
@@ -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
@@ -1,4 +1,6 @@
1
1
  require 'stendhal/mocks/test_double'
2
+ require 'stendhal/mocks/mock_verifier'
3
+ require 'stendhal/mocks/mockable'
2
4
 
3
5
  module Stendhal
4
6
  module Mocks
@@ -1,3 +1,3 @@
1
1
  module Stendhal
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
data/lib/stendhal.rb CHANGED
@@ -6,4 +6,5 @@ require 'stendhal/example'
6
6
  require 'stendhal/example_group'
7
7
 
8
8
  require 'stendhal/core_ext/kernel'
9
+ require 'stendhal/core_ext/object'
9
10
  require 'stendhal/dsl'
@@ -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
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 4
9
- version: 0.1.4
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-03 00:00:00 +01:00
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