rspec-given 3.3.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8f6b65b46cef2fc751535568e6bd4b49bab117ad
4
- data.tar.gz: 87338960a579e6e2b881c4438954733703801322
3
+ metadata.gz: 28324282e7dae4f8e019d59cc094b90e43e2c2bb
4
+ data.tar.gz: 12422b6076ce08f5c257d5da088a4753c6e6bc2f
5
5
  SHA512:
6
- metadata.gz: 2188ecabba52de943bfaff4ff22ead2808a41402b9d2d807c1afdc19c5955e53794891eff19c2f904dca4a7d220d6730b104021133f39c3fc95604262755a0b2
7
- data.tar.gz: c2b4b93337146df65592f25002cb96ce3537dc2e804b6a2cd76f81076c3b2ec126809cb6d93b9653f6b9891e745de9ff8fd9ca7ab04b915ca333a4d0c3bd8b40
6
+ metadata.gz: 931a00a40a178c7a35b6231aee226139225b6f82d4198a81ded2f0e52086d355fa5cf78f1acb18f427bcc7eced5d5a57dfa03dac5107177cf438366658c022ea
7
+ data.tar.gz: d0021d7b45dab9bf98381f992acfb6bafe6237e71d3dc8237c1e0071a08d0b438d0874321cefb2e3a73d365a864129f08fde414efc8a86649d562fa146a4e876
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  | :----: |
5
5
  | [![Master Build Status](https://secure.travis-ci.org/jimweirich/rspec-given.png?branch=master)](https://travis-ci.org/jimweirich/rspec-given) |
6
6
 
7
- Covering rspec-given, minitest-given, and given-core, version 3.3.0.beta21.
7
+ Covering rspec-given, minitest-given, and given-core, version 3.4.0.
8
8
 
9
9
  rspec-given and minitest-given are extensions to your favorite testing
10
10
  framework to allow Given/When/Then notation when writing specs.
@@ -866,6 +866,11 @@ License. See the MIT-LICENSE file in the source distribution.
866
866
 
867
867
  # History
868
868
 
869
+ * Version 3.4.0
870
+
871
+ * Bare failure objects in Then clauses will now propagate their
872
+ captured failure (added <code>to_bool</code> to failure object).
873
+
869
874
  * Version 3.3.0
870
875
 
871
876
  * Add support for <code>to_bool</code>.
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ task :tag do
42
42
  end
43
43
 
44
44
  desc "Publish the gems"
45
- task :publish => [:clobber, :gem] do
45
+ task :publish_gems => [:clobber, :gem] do
46
46
  FileList['pkg/*.gem'].each do |gemname|
47
47
  sh "gem push #{gemname}"
48
48
  end
@@ -0,0 +1,282 @@
1
+ ## Beautiful Failure Messages
2
+
3
+ The RSpec/Given library is an extension to the RSpec testing framework
4
+ that explicitly supports a Given/When/Then style for testing. It has
5
+ two goals:
6
+
7
+ * Encourage specification language when writing tests
8
+ * Allow beautiful failure messages without writing custom matchers
9
+
10
+ RSpec/Given has a been very successful in both these goals. Consider
11
+ the following spec snippet for a Page object in a Wiki Rails
12
+ application:
13
+
14
+ ```ruby
15
+ describe "content conversion to HTML" do
16
+ Given(:page) {
17
+ Page.new(
18
+ name: "HomePage",
19
+ content: "Have a _nice_ day.")
20
+ }
21
+ Then { page.html_content == "Have a <em>nice</em> day." }
22
+ end
23
+ ```
24
+
25
+ Assuming that the <code>html_content</code> method is incomplete and
26
+ not yet marking emphasized text, the failure message from the
27
+ specification will be:
28
+
29
+ 1) Page content conversion to HTML
30
+ Failure/Error: Then { page.html_content == "Have a <em>nice</em> day." }
31
+ Then expression failed at .../spec/models/page_spec.rb:38
32
+ expected: "Have a _nice_ day."
33
+ to equal: "Have a <em>nice</em> day."
34
+ false <- page.html_content == "Have a <em>nice</em> day."
35
+ "Have a _nice_ day."
36
+ <- page.html_content
37
+ #<Page name: "HomePage", content: "Have a _nice_ day." ...>
38
+ <- page
39
+ # ./spec/models/page_spec.rb:38:in `block in Then'
40
+
41
+ Let's break that down:
42
+
43
+ **It says what failed:**
44
+
45
+ Failure/Error: Then { page.html_content == "Have a <em>nice</em> day." }
46
+
47
+ **It says where it failed:**
48
+
49
+ Then expression failed at .../spec/models/page_spec.rb:38
50
+
51
+ **It says what was expected:**
52
+
53
+ expected: "Have a _nice_ day."
54
+ to equal: "Have a <em>nice</em> day."
55
+
56
+ **It then breaks down each subexpression and displays its value:**
57
+
58
+ false <- page.html_content == "Have a <em>nice</em> day."
59
+ "Have a _nice_ day."
60
+ <- page.html_content
61
+ #<Page name: "HomePage", content: "Have a _nice_ day." ...>
62
+ <- page
63
+
64
+ All of this happens without the developer needing to write any special
65
+ error matchers or custom output. Everything you need to debug a spec
66
+ failure is there in the output.
67
+
68
+ ## A More Complex Example
69
+
70
+ Let's look at a more complex example. Suppose we want to test
71
+ validations in the Page object. For example, we might want to make
72
+ sure that:
73
+
74
+ * The page has a name
75
+ * The name conforms to the standard wiki naming convention (i.e. WikiName).
76
+
77
+ Here's the beginning of that specification:
78
+
79
+ ```ruby
80
+ describe Page do
81
+ VALID_ATTRS = { name: "SomePage", content: "CONTENT" }
82
+ Given(:attrs) { VALID_ATTRS }
83
+ Given(:page) { Page.new(attrs) }
84
+
85
+ ...
86
+ end
87
+ ```
88
+
89
+ <code>VALID\_ATTRS</code> is a list of attributes that will construct a
90
+ valid page object. Normally I would put <code>VALID\_ATTRS</code> in something like
91
+ Factory Girl, but a simple constant is good enough this example.
92
+
93
+ I then declare a given that <code>attrs</code> is the valid
94
+ attributes, and that <code>Page</code> is constructed from these valid
95
+ attributes.
96
+
97
+ I can now describe a valid page object.
98
+
99
+ ```ruby
100
+ context "with valid attributes" do
101
+ Then { page.valid? }
102
+ end
103
+ ```
104
+
105
+ To describe a validation failure where the name is missing, I create a
106
+ context where I override the default <code>attrs</code> with a version
107
+ that omits the name.
108
+
109
+ ```ruby
110
+ context "with missing name" do
111
+ Given(:attrs) { VALID_ATTRS.merge(name: nil) }
112
+ Then { page.invalid? }
113
+ And { ! page.errors[:name].empty? }
114
+ And { page.errors[:name].any? { |msg| msg =~ /blank/ } }
115
+ end
116
+ ```
117
+
118
+ Why Then/And/And? Because there are three things that should be true
119
+ if a validation fails.
120
+
121
+ 1. The object must not be valid
122
+ 2. The field that has the error must have error messages
123
+ 3. At least one of the error messages should mention the word 'blank'
124
+
125
+ Suppose the Page object has a validation on name, but doesn't check
126
+ for presence. The failure message clearly tells you that the spec
127
+ failed because no error messages on the <code>name</code> field
128
+ mentioned 'blank'.
129
+
130
+ 1) Page validations with missing name
131
+ Failure/Error: Then { page.invalid? }
132
+ And expression failed at ./spec/models/page_spec.rb:27
133
+ Failing expression: And { page.errors[:name].any? { |msg| msg =~ /blank/ } }
134
+ false <- page.errors[:name].any? { |msg| msg =~ /blank/ }
135
+ ["is not a wiki name"]
136
+ <- page.errors[:name]
137
+ #<ActiveModel::Errors:... @messages={:name=>["is not a wiki name"]}>
138
+ <- page.errors
139
+ #<Page name: nil, content: "CONTENT", ...>
140
+ <- page
141
+ # ./spec/models/page_spec.rb:25:in `block in Then'
142
+
143
+ We get informative error messages, which is exactly what we want.
144
+
145
+ However, the spec itself is a little wordy, with repeating
146
+ Then/And/And. What if we wrote a simple query function that checked
147
+ for the three conditions and reported true/false accordingly.
148
+
149
+ ```ruby
150
+ def invalid?(page, field, pattern)
151
+ page.invalid? &&
152
+ ! page.errors[field].empty? &&
153
+ page.errors[field].any? { |msg| msg =~ pattern }
154
+ end
155
+ ```
156
+
157
+ Now we can use <code>invalid?</code> in all our validations
158
+ specifications:
159
+
160
+ ```ruby
161
+ context "with missing name" do
162
+ Given(:attrs) { VALID_ATTRS.merge(name: nil) }
163
+ Then { invalid?(page, :name, /blank/) }
164
+ end
165
+ ```
166
+
167
+ But there is a downside. Because <code>invalid?</code> only returns
168
+ true/false, and there are no mention of the <code>errors</code> object
169
+ in the Then clause, the failure message is really uninformative:
170
+
171
+ 1) Page validations with missing name
172
+ Failure/Error: Then { invalid_on(page, :name, /blank/) }
173
+ Then expression failed at ./spec/models/page_spec.rb:31
174
+ false <- invalid_on(page, :name, /blank/)
175
+ #<Page name: nil, content: "CONTENT", ...>
176
+ <- page
177
+ # ./spec/models/page_spec.rb:31:in `block in Then'
178
+
179
+ All we know is that the page is invalid. We get no indication of what
180
+ fields were actually in error and what the error messages actually
181
+ were.
182
+
183
+ ## Custom Failure Message
184
+
185
+ By abstracting away the details how to check for invalid models (which
186
+ is generally a good thing), RSpec/Given lost the ability to give us
187
+ the details of why it failed.
188
+
189
+ Fortunately, there is a simple fix. Instead of returning a simple
190
+ true/false value, the <code>invalid?</code> method should return an
191
+ object, that when inspected, tells why it failed.
192
+
193
+ If a _Then_ clause returns a value that supports a
194
+ <code>to_bool</code> method, then RSpec/Given will call that method
195
+ before checking for true/false (in rspec-given 3.3.0 or later). All we
196
+ need to do is arrange for that object to be returned.
197
+
198
+ ```ruby
199
+ def must_be_invalid(model, field, pattern=//)
200
+ MustBeInvalid.new(model, field, pattern)
201
+ end
202
+ ```
203
+
204
+ Since the method no longer returns a true/false value, I've changed
205
+ the name from <code>invalid?</code> to <code>must\_be\_invalid</code>.
206
+
207
+ The code for the <code>MustBeInvalid</code> class is a bit long, but
208
+ there is nothing complex in it. The <code>to_bool</code> method
209
+ carefully checks for each of our three conditions and records the
210
+ exact reason for failure in the @why instance variable. The
211
+ <code>inspect</code> method (called by RSpec/Given to display its
212
+ value) just returns the @why value with additional details about the
213
+ errors on the object.
214
+
215
+ ```ruby
216
+ class MustBeInvalid
217
+ def initialize(model, field, pattern)
218
+ @model = model
219
+ @field = field
220
+ @pattern = pattern
221
+ @why = nil
222
+ end
223
+
224
+ def to_bool
225
+ if @model.valid?
226
+ @why = "#{@model.class} was valid (expected invalid)"
227
+ false
228
+ elsif @model.errors[@field].empty?
229
+ @why = "#{@model.class} had no errors on field #{@field}" +
230
+ error_descriptions
231
+ false
232
+ elsif @model.errors[@field].none? { |msg| msg =~ @pattern }
233
+ @why = "#{@model.class} had no errors " +
234
+ "matching #{@pattern} on field #{@field}" +
235
+ error_descriptions
236
+ false
237
+ else
238
+ @why = "OK (expected invalid)"
239
+ true
240
+ end
241
+ end
242
+
243
+ def inspect
244
+ to_bool if @why.nil?
245
+ @why
246
+ end
247
+
248
+ private
249
+
250
+ def error_descriptions
251
+ if @model.errors.empty?
252
+ ""
253
+ else
254
+ "\n Errors were:\n * " +
255
+ @model.errors.full_messages.
256
+ map { |msg| msg }.join("\n * ")
257
+ end
258
+ end
259
+ end
260
+ ```
261
+
262
+ The failure message returned by <code>MustBeInvalid</code> is once
263
+ again clear and to the point. It contains all the information needed
264
+ for debugging.
265
+
266
+ 1) Page validations with missing name
267
+ Failure/Error: Then { must_be_invalid(page, :name, /blank/) }
268
+ Then expression failed at ./spec/models/page_spec.rb:31
269
+ Page had no errors matching (?-mix:blank) on field name
270
+ Errors were:
271
+ * Name is not a wiki name
272
+ <- must_be_invalid(page, :name, /blank/)
273
+ #<Page name: nil, content: "CONTENT", ...>
274
+ <- page
275
+ # ./spec/models/page_spec.rb:31:in `block in Then'
276
+
277
+ ## Summary
278
+
279
+ I've always felt that you can tell the maturity level of a piece of
280
+ software by the beauty of the error messages it produces. By
281
+ providing the ability to do custom messages where needed, RSpec/Given
282
+ takes a step in that direction.
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Failing Then clauses" do
4
+
5
+ # NOTE: FAIL and ERROR are special versions of the Then clause that
6
+ # expect failures and errors. These are used only in the framework
7
+ # testing and are not generally available.
8
+
9
+ context "with false" do
10
+ FAIL { false }
11
+ end
12
+
13
+ context "with exception comparison in when result" do
14
+ When(:result) { fail "explicitly" }
15
+ ERROR { result == 1 }
16
+ end
17
+
18
+ context "with bare exception in when result" do
19
+ When(:result) { fail "explicitly" }
20
+ ERROR { result }
21
+ end
22
+
23
+ end
@@ -0,0 +1,31 @@
1
+ require 'rspec/given'
2
+
3
+ # These extensions are used for framework testing, where failing a
4
+ # Then block is a passing condition.
5
+ module Given
6
+ module InstanceExtensions
7
+ NotMetError = RSpec::Expectations::ExpectationNotMetError
8
+
9
+ def _gvn_fail(&block)
10
+ expect { _gvn_then(&block) }.to raise_error(NotMetError)
11
+ end
12
+
13
+ def _gvn_error(&block)
14
+ expect { _gvn_then(&block) }.to raise_error(StandardError)
15
+ end
16
+ end
17
+
18
+ module ClassExtensions
19
+
20
+ # Fails spec if block passes.
21
+ def FAIL(&block)
22
+ Then(on_eval: "_gvn_fail", &block)
23
+ end
24
+
25
+ # Fails spec if block does not raise some kind of error.
26
+ def ERROR(&block)
27
+ Then(on_eval: "_gvn_error", &block)
28
+ end
29
+
30
+ end
31
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-given
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Weirich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-20 00:00:00.000000000 Z
11
+ date: 2013-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: given_core
@@ -16,26 +16,26 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 3.3.0
19
+ version: 3.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 3.3.0
26
+ version: 3.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '2.12'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.12'
41
41
  description: |
@@ -52,6 +52,29 @@ files:
52
52
  - README.md
53
53
  - Rakefile
54
54
  - TODO
55
+ - doc/article/custom_error_messages.md
56
+ - doc/main.rdoc
57
+ - examples/example_helper.rb
58
+ - examples/failing/natural_failing_spec.rb
59
+ - examples/failing/sample_spec.rb
60
+ - examples/integration/and_spec.rb
61
+ - examples/integration/failing/eval_subexpression_spec.rb
62
+ - examples/integration/failing/module_nesting_spec.rb
63
+ - examples/integration/failing/to_bool_returns_false.rb
64
+ - examples/integration/failing/undefined_method_spec.rb
65
+ - examples/integration/failing_messages_spec.rb
66
+ - examples/integration/focused_line_spec.rb
67
+ - examples/integration/given_spec.rb
68
+ - examples/integration/invariant_spec.rb
69
+ - examples/integration/then_spec.rb
70
+ - examples/loader.rb
71
+ - examples/minitest/assert_raises_spec.rb
72
+ - examples/minitest_helper.rb
73
+ - examples/other/line_example.rb
74
+ - examples/stack/stack.rb
75
+ - examples/stack/stack_spec.rb
76
+ - examples/stack/stack_spec1.rb
77
+ - examples/use_assertions.rb
55
78
  - lib/given.rb
56
79
  - lib/rspec-given.rb
57
80
  - lib/rspec/given.rb
@@ -65,6 +88,7 @@ files:
65
88
  - spec/lib/given/ext/numeric_spec.rb
66
89
  - spec/lib/given/ext/numeric_specifications.rb
67
90
  - spec/lib/given/extensions_spec.rb
91
+ - spec/lib/given/failing_thens_spec.rb
68
92
  - spec/lib/given/failure_matcher_spec.rb
69
93
  - spec/lib/given/failure_spec.rb
70
94
  - spec/lib/given/file_cache_spec.rb
@@ -77,57 +101,36 @@ files:
77
101
  - spec/lib/given/options_spec.rb
78
102
  - spec/spec_helper.rb
79
103
  - spec/support/be_booleany.rb
104
+ - spec/support/failure_and_errors.rb
80
105
  - spec/support/faux_then.rb
81
106
  - spec/support/natural_assertion_control.rb
82
- - examples/example_helper.rb
83
- - examples/failing/natural_failing_spec.rb
84
- - examples/failing/sample_spec.rb
85
- - examples/integration/and_spec.rb
86
- - examples/integration/failing/eval_subexpression_spec.rb
87
- - examples/integration/failing/module_nesting_spec.rb
88
- - examples/integration/failing/to_bool_returns_false.rb
89
- - examples/integration/failing/undefined_method_spec.rb
90
- - examples/integration/failing_messages_spec.rb
91
- - examples/integration/focused_line_spec.rb
92
- - examples/integration/given_spec.rb
93
- - examples/integration/invariant_spec.rb
94
- - examples/integration/then_spec.rb
95
- - examples/loader.rb
96
- - examples/minitest/assert_raises_spec.rb
97
- - examples/minitest_helper.rb
98
- - examples/other/line_example.rb
99
- - examples/stack/stack.rb
100
- - examples/stack/stack_spec.rb
101
- - examples/stack/stack_spec1.rb
102
- - examples/use_assertions.rb
103
- - doc/main.rdoc
104
107
  homepage: http://github.com/jimweirich/rspec-given
105
108
  licenses:
106
109
  - MIT
107
110
  metadata: {}
108
111
  post_install_message:
109
112
  rdoc_options:
110
- - --line-numbers
111
- - --inline-source
112
- - --main
113
+ - "--line-numbers"
114
+ - "--inline-source"
115
+ - "--main"
113
116
  - doc/main.rdoc
114
- - --title
117
+ - "--title"
115
118
  - RSpec Given Extensions
116
119
  require_paths:
117
120
  - lib
118
121
  required_ruby_version: !ruby/object:Gem::Requirement
119
122
  requirements:
120
- - - '>='
123
+ - - ">="
121
124
  - !ruby/object:Gem::Version
122
125
  version: 1.9.2
123
126
  required_rubygems_version: !ruby/object:Gem::Requirement
124
127
  requirements:
125
- - - '>='
128
+ - - ">="
126
129
  - !ruby/object:Gem::Version
127
130
  version: '0'
128
131
  requirements: []
129
132
  rubyforge_project: given
130
- rubygems_version: 2.1.11
133
+ rubygems_version: 2.2.0
131
134
  signing_key:
132
135
  specification_version: 4
133
136
  summary: Given/When/Then Specification Extensions for RSpec.