riot 0.10.11 → 0.10.12.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +3 -1
  2. data/CHANGELOG +34 -0
  3. data/README.markdown +81 -456
  4. data/Rakefile +31 -28
  5. data/VERSION +1 -1
  6. data/lib/riot.rb +2 -1
  7. data/lib/riot/assertion.rb +1 -1
  8. data/lib/riot/assertion_macro.rb +51 -5
  9. data/lib/riot/assertion_macros/any.rb +1 -1
  10. data/lib/riot/assertion_macros/assigns.rb +2 -2
  11. data/lib/riot/assertion_macros/empty.rb +1 -1
  12. data/lib/riot/assertion_macros/equals.rb +4 -4
  13. data/lib/riot/assertion_macros/equivalent_to.rb +22 -0
  14. data/lib/riot/assertion_macros/includes.rb +2 -2
  15. data/lib/riot/assertion_macros/kind_of.rb +2 -2
  16. data/lib/riot/assertion_macros/matches.rb +2 -2
  17. data/lib/riot/assertion_macros/nil.rb +1 -1
  18. data/lib/riot/assertion_macros/raises.rb +7 -10
  19. data/lib/riot/assertion_macros/respond_to.rb +3 -2
  20. data/lib/riot/assertion_macros/same_elements.rb +1 -1
  21. data/lib/riot/assertion_macros/size.rb +2 -2
  22. data/lib/riot/context.rb +104 -19
  23. data/lib/riot/message.rb +23 -0
  24. data/lib/riot/rr.rb +35 -0
  25. data/lib/riot/runnable.rb +12 -0
  26. data/lib/riot/situation.rb +4 -0
  27. data/riot.gemspec +20 -4
  28. data/test/assertion_macro_test.rb +30 -0
  29. data/test/assertion_macros/assigns_test.rb +3 -3
  30. data/test/assertion_macros/equals_test.rb +2 -9
  31. data/test/assertion_macros/equivalent_to_test.rb +36 -0
  32. data/test/assertion_macros/respond_to_test.rb +1 -0
  33. data/test/assertion_macros/size_test.rb +6 -6
  34. data/test/assertion_test.rb +1 -1
  35. data/test/benchmark/message_concatenation.rb +82 -0
  36. data/test/context_test.rb +17 -2
  37. data/test/extensions/rrriot_test.rb +69 -0
  38. data/test/message_test.rb +35 -0
  39. data/test/teststrap.rb +1 -1
  40. metadata +27 -4
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  *.gem
2
2
  pkg
3
- .*.swp
3
+ .*.swp
4
+ doc
5
+ .yardoc
data/CHANGELOG CHANGED
@@ -1,3 +1,37 @@
1
+ *0.10.12.pre*
2
+
3
+ * RR support in Riot [vandrijevik,jaknowlden]
4
+
5
+ # teststrap.rb
6
+ require 'riot'
7
+ Riot.rr
8
+
9
+ # your-test.rb
10
+ context "foo" do
11
+ setup do
12
+ mock!.hello {"world"}
13
+ end
14
+
15
+ asserts("failure due to not calling hello") { true } # actually fails
16
+ end
17
+
18
+ * Added Riot::Message to make messages in macros easier to write [jaknowlden]
19
+
20
+ def evaluate(actual, expected)
21
+ # ...
22
+ expected == actual pass(new_message.received(expected)) ? fail(expected(expected).not(actual))
23
+ # ...
24
+ end
25
+
26
+ * Added responds_to as a respond_to alias [jaknowlden]
27
+
28
+ * Added the equivalent_to macro to compare case equality (===). equals is now (==) [jaknowlden]
29
+
30
+ * Assuming RootContext if nil parent provided. Added Context#parent to the API [jaknowlden]
31
+
32
+ Riot::Context.new("Hi", nil) {}.parent.class
33
+ => Riot::RootContext
34
+
1
35
  *0.10.11*
2
36
 
3
37
  * Context#asserts_topic now takes an optional description [gabrielg, jaknowlden]
@@ -1,509 +1,134 @@
1
1
  # Riot
2
2
 
3
- An extremely fast, expressive, and context-driven unit-testing framework. Protest the slow test.
4
-
5
- ## Contents
6
-
7
- - [Installation](#installation)
8
- - [Note on speed](#speed)
9
- - [Examples](#examples)
10
- - [Boolean](#examples-boolean)
11
- - [Shortcuts](#examples-shortcut)
12
- - [Equality](#examples-equality)
13
- - [Matches](#examples-matches)
14
- - [Raises](#examples-raises)
15
- - [Kind Of](#examples-kind-of)
16
- - [Empty](#examples-empty)
17
- - [Respond To](#examples-respond-to)
18
- - [Assigns](#examples-assigns)
19
- - [Nested contexts](#examples-nested)
20
- - [Block expectations](#examples-block)
21
- - [OMG! Why did you write this](#omg)
22
- - [Running tests](#running)
23
- - [With Sinatra](#sinatra)
24
- - [With Rails](#rails)
25
- - [Extending Riot with Macros](#extending)
26
- - [Assertion macros](#assertion-macros)
27
-
28
- When you're done reading here, take a gander at:
29
-
30
- * [Riot Rails](http://github.com/thumblemonks/riot_rails): Rails support for Riot testing. A definite work in progress (help welcomed). See [evoke-app](http://github.com/thumblemonks/evoke-app) for live examples.
31
- * [Riot.js](http://github.com/alexyoung/riotjs): for you JavaScript people, a version of Riot just for you. Both implementations will be informing the other. Lots of stuff to learn.
32
-
33
- <a name="installation"></a>
34
- #### Installation
35
-
36
- The Riot gem is hosted on gemcutter.org. It used to be hosted on GitHub, but they turned off gem support while moving to Rackspace, so we moved to gemcutter. If you have not already done so, add gemcutter.org to your list of gem sources like so:
3
+ A fast, expressive and concise unit-testing framework.
37
4
 
38
- sudo gem sources -a http://gemcutter.org
39
-
40
- Then, simply install the Riot gem like so:
41
-
42
- sudo gem install riot
43
-
44
- <a name="speed"></a>
45
- #### Note on speed
46
-
47
- I have done a really simple benchmarking (10,000 runs), but right now, Riot is running about **3 times** faster than Test::Unit and thusly Shoulda:
48
-
49
- Rehearsal ----------------------------------------------
50
- Riot 0.360000 0.000000 0.360000 ( 0.364236)
51
- Test::Unit 1.250000 0.000000 1.250000 ( 1.258466)
52
- Shoulda 1.270000 0.010000 1.280000 ( 1.277429)
53
- ------------------------------------- total: 2.890000sec
54
-
55
- user system total real
56
- Riot 0.360000 0.000000 0.360000 ( 0.353360)
57
- Test::Unit 1.260000 0.000000 1.260000 ( 1.263777)
58
- Shoulda 1.270000 0.000000 1.270000 ( 1.270957)
59
-
60
- "Is it valid?", you ask. *I* think it is. I ain't no cheater, but I might be delusional.
61
-
62
- To compare against MiniTest, I had to run the benchmark separately.
63
-
64
- Rehearsal --------------------------------------------
65
- Riot 0.350000 0.000000 0.350000 ( 0.354331)
66
- MiniTest 0.720000 0.070000 0.790000 ( 0.793093)
67
- ----------------------------------- total: 1.140000sec
68
-
69
- user system total real
70
- Riot 0.350000 0.000000 0.350000 ( 0.348796)
71
- MiniTest 0.730000 0.060000 0.790000 ( 0.801629)
72
-
73
- Riot is currently about twice as fast as minitest. Riot is also half the code of MiniTest (`310 loc < 674 loc` :)
74
-
75
- All tests ran with `ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9.8.0], MBARI 0x8770, Ruby Enterprise Edition 2009.10`.
76
-
77
- Riot also works very well with Ruby 1.9. The same benchmarks from above run through ruby-1.9 show Riot to be twice as fast as it is already. See our [benchmarks gist](http://gist.github.com/240353) for more details.
78
-
79
- <a name="examples"></a>
80
- ## Examples
81
-
82
- <a name="examples-boolean"></a>
83
- #### Example: Basic booleans
84
-
85
- **NOTE:** For no specific reason, I'm going to use an ActiveRecord model in the following examples.
86
-
87
- At it's very basic, Riot simply tries to assert that an expression is true or false. Riot does this through its `asserts` or `should` tests. An `asserts` test will pass if the result of running the test is neither `nil` or `false`. A `should` test does the exact same thing - they are in effect, aliases. The only difference is in the way you write the assertion.
88
-
89
- For instance, given a test file named `foo_test.rb`, you might have the following code in it:
90
-
91
- require 'riot'
92
-
93
- context "a new user" do
94
- setup { User.new }
95
- asserts("that it is not yet created") { topic.new_record? }
96
- teardown { #cleanup here }
97
- end
98
-
99
- Notice that you do not define a class anywhere. That would be the entire contents of that test file. If you wanted to use a `should` instead, you could say this:
100
-
101
- require 'riot'
102
-
103
- context "a new user" do
104
- setup { User.new }
105
- should("not be created") { topic.new_record? }
106
- end
107
-
108
- Sometimes it's more clear to say "this **should** be that" and sometimes it's better to say "**asserts** this is that". I promise you that Riot will get no more redundant than this, but also that besides speed, Riot will aim at being expressive with a minimal amount of syntax.
109
-
110
- The other important thing to note in the examples above is the use of the `topic`. Calling `topic` within any assertion will actually return the value of whatever was evaluated and returned from calling the last setup in the given context. In the examples above, `User.new` was returned, and is therefor accessible as the `topic`.
111
-
112
- I'm going to use `asserts` for the rest of this introduction, but you should know that you can replace any instance of `asserts` with `should` and nothing would change.
113
5
 
114
- <a name="examples-shortcut"></a>
115
- #### Example: Shortcuts
6
+ ## Installation
116
7
 
117
- ##### Asserting the topic itself
118
- Over the course of developing Riot it became somewhat obvious to some of us that we were creating assertions that returned the `topic` just so we could assert things about the topic itself. For instance, were doing this:
8
+ Add Gemcutter to your gem sources:
119
9
 
120
- context "a billionaire" do
121
- setup { MoneyMaker.build(:billionaire) }
122
-
123
- should("be a Billionaire") { topic }.kind_of(Billionaire)
124
- end
125
-
126
- This is awfully redundant - not to mention, contrived. So, we wrote a shortcut to generate an assertion that returns topic. This means we can now do this:
127
-
128
- context "a billionaire" do
129
- setup { MoneyMaker.build(:billionaire) }
130
- asserts_topic.kind_of(Billionaire)
131
- end
132
-
133
- If you'd like to add a description to your assertion about the topic, but still would like to avoid the redundancy of an assertion simply returning the topic from it's block, you can omit the block all together as follows:
134
-
135
- context "a trazillionaire" do
136
- setup { MoneyMaker.build(:trazillionaire) }
137
- asserts("is a trazillionaire").kind_of(Trazillionaire)
138
- end
139
-
140
- ##### Asserting methods on topic
141
-
142
- A very common assertion pattern with Riot is calling a method on the topic and asserting it's output. For instance, the following is not an uncommon thing to see in an `ActiveRecord` test:
143
-
144
- context "A new post" do
145
- setup { Post.new(:name => "Howdy ya'll") }
146
- asserts("name") { topic.name }.equals("Howdy ya'll")
147
- end
148
-
149
- Since Riot is all about reducing redundancy and increasing semantics, it makes a ton of sense to be able to do this instead:
150
-
151
- context "A new post" do
152
- setup { Post.new(:name => "Howdy ya'll") }
153
- asserts(:name).equals("Howdy ya'll")
154
- end
155
-
156
- And now you can! Isn't that just so much easier to read?
157
-
158
- <a name="examples-equality"></a>
159
- #### Example: Equality
160
-
161
- One of the most common assertions you will (or do already) utilize is that of equality; is this equal to that? Riot supports this in a slightly different manner than most other frameworks. With Riot, you add the expectation to the assertion itself.
162
-
163
- For example:
164
-
165
- context "a new user" do
166
- setup { User.new(:email => 'foo@bar.com') }
167
- asserts("email address") { topic.email }.equals('foo@bar.com')
168
- end
169
-
170
- Here, you should begin to notice that tests themselves return the actual value. You do not write assertions into the test. Assertions are "aspected" onto the test. If the test above did not return 'foo@bar.com' for `topic.email`, the assertion would have failed.
171
-
172
- The `equals` modifier works with any type of value, including nil's. However, if you wanted to test for nil explicitly, you could simply do this:
173
-
174
- context "a new user" do
175
- setup { User.new }
176
- asserts("email address") { topic.email }.nil
177
- end
178
-
179
- Notice the `nil` modifier added to asserts. Also notice how the test almost reads as "a new user asserts email address *is* nil". With Test::Unit, you would have probably written:
180
-
181
- class UserTest < Test::Unit::TestCase
182
- def setup
183
- @user = User.new
184
- end
185
-
186
- def test_email_address_is_nil
187
- assert_nil @user.email
188
- end
189
- end
190
-
191
- Which, to me, seems like a redundancy. The test already says it's nil! Maybe Shoulda woulda helped:
192
-
193
- class UserTest < Test::Unit::TestCase
194
- def setup
195
- @user = User.new
196
- end
197
-
198
- should "have nil email" { assert_nil @user.email }
199
- end
200
-
201
- In my opinion, the same redundancy exists. Sure, I could write a macro like `should_be_nil {@user.email}`, but the redundancy exists in the framework itself.
202
-
203
- <a name="examples-matches"></a>
204
- #### Example: Matches
205
-
206
- If you need to assert that a test result matches a regular expression, use the `matches` modifier like so:
207
-
208
- context "a new user" do
209
- setup { User.new }
210
-
211
- # I'm a contrived example
212
- asserts("random phone number") { topic.random_phone_number }.matches(/^\d{3}-\d{3}-\d{4}$/)
213
- end
214
-
215
- <a name="examples-raises"></a>
216
- #### Example: Raises
217
-
218
- Sometimes, your test raises an exception that you actually expected.
219
-
220
- context "a new user" do
221
- setup { User.new }
222
- asserts("invalid data") { topic.save! }.raises(ActiveRecord::RecordInvalid)
223
- end
224
-
225
- And if you wanted to check that the exception and message match what you expect:
226
-
227
- context "a new user" do
228
- setup { User.new }
229
- asserts("invalid data") { topic.save! }.raises(ActiveRecord::RecordInvalid, /has errors/)
230
- end
231
-
232
- <a name="examples-kind-of"></a>
233
- #### Example: Kind Of
234
-
235
- When you want to test that an expression returns an object of an expected type:
236
-
237
- context "a new user" do
238
- setup { User.new }
239
- asserts("its balance") { topic.balance }.kind_of(Currency)
240
- end
241
-
242
- <a name="examples-empty"></a>
243
- #### Example: Empty
244
-
245
- When you want to assert a test result is empty (length == 0):
246
-
247
- context "a new user" do
248
- setup { User.new }
249
- should("have no first name") { topic.first_name }.empty
250
-
251
- #let's imagine phone numbers is an array
252
- should("have no phone numbers") { topic.phone_numbers }.empty
253
-
254
- #let's imagine attributes is a hash
255
- should("have no attributes") { topic.attributes }.empty
256
- end
257
-
258
- <a name="examples-respond-to"></a>
259
- #### Example: Respond To
10
+ !!!plain
11
+ sudo gem sources -a http://gemcutter.org
260
12
 
261
- When you want to test that an object responds to a specific method:
13
+ Then, simply install the Riot gem like so:
262
14
 
263
- context "a new user" do
264
- setup { User.new }
265
- asserts("email is defined") { topic }.respond_to(:email)
266
- end
15
+ !!!plain
16
+ sudo gem install riot
267
17
 
268
- <a name="examples-assigns"></a>
269
- #### Example: Assigns
270
18
 
271
- Sometimes you want to check and see if an instance variable is defined.
19
+ ## Usage
272
20
 
273
- context "a new user" do
274
- setup do
275
- User.new(:email => "foo@bar.baz", :first_name => nil)
276
- end
277
- asserts("has an email address") { topic }.assigns(:email)
278
- asserts("has a first name") { topic }.assigns(:first_name) # This will fail
279
- end
21
+ In contrast to other popular Ruby testing frameworks such as Test::Unit,
22
+ [Shoulda](http://github.com/thoughtbot/shoulda) and [RSpec](http://rspec.info/),
23
+ Riot does not run a `setup` and `teardown` sequence before and after each test. This speeds
24
+ up the test runs quite a bit, but also puts restrictions on how you write your tests. In
25
+ general, you should avoid mutating any objects under test.
280
26
 
281
- While other times you also want to make sure the value of the instance variable is what you expect it to be.
27
+ In Riot, tests reside in *contexts*. Within these, a *topic* object is defined through a
28
+ `setup` block. The actual assertions are then made with `assert`.
282
29
 
283
- context "a new user" do
284
- setup do
285
- User.new(:email => "foo@bar.baz", :first_name => "John")
286
- end
287
- asserts("has an email address") { topic }.assigns(:email, "foo@bar.baz")
288
- asserts("has a first name") { topic }.assigns(:first_name, "Joe") # This will fail
30
+ context "An Array" do
31
+ setup { Array.new }
32
+ asserts("is empty") { topic.empty? }
289
33
  end
290
34
 
291
- <a name="examples-nested"></a>
292
- #### Example: Nested contexts
35
+ As you can see, the setup block doesn't use any instance variables to save the object under
36
+ test -- rather, the return value of the block is used as the *topic*. This object can then
37
+ be accessed in the assertions using the `topic` attribute.
293
38
 
294
- Oh yeah, Riot does those, too. The `setup` from each parent is "loaded" into the context and then the context is executed as normal. Test naming is a composite of the parent contexts' names. Here, we'll do a little Sinatra testing (see below for instructions on how to make it Riot work seamlessly with Sinatra tests).
39
+ Furthermore, assertions need only return a boolean; `true` indicates a pass, while `false`
40
+ indicates a fail.
295
41
 
296
- context "My App:" do
297
- setup { @app = MyApp }
42
+ Contexts can also be nested; the `setup` blocks are executed outside-in before.
298
43
 
299
- context "get /" do
300
- setup { get '/' }
301
- # ...
302
- # assertions
44
+ context "An Array" do
45
+ setup { Array.new }
303
46
 
304
- context "renders a body" do
305
- setup { @body = last_response.body }
306
- # ...
307
- # assertions
308
- end
309
- end
310
-
311
- context "get /books/1" do
312
- setup { get '/books/1' }
313
- # ...
314
- # assertions
47
+ context "with one element" do
48
+ setup { topic << "foo" }
49
+ asserts("is not empty") { !topic.empty? }
50
+ asserts("returns the element on #first") { topic.first == "foo" }
315
51
  end
316
52
  end
317
53
 
318
- <a name="examples-block"></a>
319
- #### Example: Block expectations
320
-
321
- You can use a block to create the expected value for your assertion,
322
- which might come in useful if it takes a bit of work to generate your
323
- expected value. My apologies for the incredibly contrived example as so:
324
-
325
- context "block expectations" do
326
- setup { 2 }
327
- asserts_topic.equals { 1 + 1 }
328
- end
329
-
330
- #### More examples/documentation
331
-
332
- There are many more basic assertion modifiers to come. See below for writing Riot extensions if you want to help out.
333
-
334
- See the TODO section for everything that's missing.
335
-
336
- Also, see [the wiki](http://wiki.github.com/thumblemonks/riot) for more examples and documentation.
337
-
338
- <a name="omg"></a>
339
- ## You say, "OMG! Why did you write this?"
340
-
341
- ### Some background, I guess
342
-
343
- You start a new project. You get all excited. You're adding tests. You're adding factories. You're fixturating your setups. You're adding more tests. Your tests start slowing down, but you need to keep pushing because your backlog has a lot of new, nifty features in it. You've got 3000+ lines of test code, 2000+ assertions. Your tests are annoyingly slow. Your tests have become a burden.
344
-
345
- I hate this and it happens a lot, even when I'm conscience that it's happening. Even when I'm not hitting the database and I'm mocking the crap out my code.
346
-
347
- I really, really hate slow test suites.
348
-
349
- #### Did ... you look at Shoulda
350
-
351
- I should say that I love Shoulda in theory and in practice. It changed the way I coded. I added macros all over the place. I built macros into the gems I wrote for the gem itself. But, alas, Shoulda is slow. Shoulda is based on Test::Unit. Shoulda reruns setups for every should. Shoulda could make my life even easier with even more expressiveness.
352
-
353
- #### Did ... you look at RSpec
354
-
355
- :| yes, no, I don't care. It's slow, too. Anyways, I was at [ObjectMentor](http://objectmentor.com) many, many moons ago when Dave Astels (accompanied by David Chelimsky) were explaining this brand new approach to testing called BDD. Mr. Astels explained to us that we if we already understood TDD, then BDD wouldn't help a bunch. Why argue with him?
356
-
357
- ### How Riot is the same
358
-
359
- 1. It defines a context
360
- 1. It prints .'s, F's, and E's when tests pass, fail, or error
361
- 1. It tells you how long it took to run just the tests
362
- 1. Contexts can be nested and setups inherited
363
54
 
364
- ### How Riot is different
55
+ ### Using assertion macros
365
56
 
366
- Riot differs primarily in that it does not rerun setup for each test in a context. I know this is going to shock a lot of folks. However, over the past several years of my doing TDD in some capacity or another, there are certain habits I have tried to pick up on any many others I have tried to drop.
57
+ Macros greatly simplify a lot of assertions by capturing common practises, e.g. comparing
58
+ some value using the `==` operator. They work by calling the macro method on the return
59
+ value of `asserts`:
367
60
 
368
- For instance, I believe that no assertion should mangle the context of
369
- the test data it is running in. Following this allows me to require
370
- setup be run only once for a collection of related assertions. Even in
371
- a nested context where setups are inherited, the setup's are called
372
- only once per the specific context. Furthermore, teardowns are also
373
- called only once per the specific context, after all the setups and
374
- assertions have run.
61
+ asserts("#first") { topic.first }.equals("foo")
375
62
 
376
- Following all of this allows me to have very fast tests (so far).
63
+ Other macros are available; for a complete overview, see {Riot::AssertionMacro}.
377
64
 
378
- ...
65
+ A common pattern is to make assertions on the return value of some attribute or method
66
+ on the `topic` -- to simplify this, we have provided an easy to use shorthand. Simply
67
+ give a Symbol as the first argument to `asserts` and leave out the block.
379
68
 
380
- Riot is also different in that assertions are not added to the test block. Each test block is it's own assertion (and assertion block). Whatever the result is of processing an assertion block will be used to determine if an assertion passed or failed. Each assertion block can have a specific validator tied to it for asserting any number of things, like: the result of the test **equals** some expected value, the result of the test **matches** some expected expression, or the result of the test **raises** some exception.
69
+ asserts(:first).equals("foo")
381
70
 
382
- I like this approach because I only want to test one thing, but that one thing may require some work on my behalf to get the value. Riot does not let me cheat in this regard. There is no way for me to add more than one assertion to an assertion block.
383
71
 
384
- ...
72
+ ### Reading Riot's output
385
73
 
386
- I imagine this approach will persuade many of you to avoid Riot altogether. I don't blame you. A few years ago I would have avoided it, too. As of this writing though, I have ported Chicago and Slvu (which were previously written in Test::Unit + Shoulda) to Riot, cut the number of lines of code in almost half, definitely more than halved the amount of time the tests took to run, and did so in less than half a day (I was building Riot while porting them :).
74
+ Riot can output the test results in several ways, the default being *story reporting*. With
75
+ this reporter, the output looks like the following:
387
76
 
388
- <a name="running"></a>
389
- ## Running tests
390
-
391
- Create or modify your existing Rakefile to define a test task like so:
392
-
393
- desc 'Default task: run all tests'
394
- task :default => [:test]
77
+ !!!plain
78
+ An Array
79
+ + asserts is empty
80
+ An Array with one element
81
+ + asserts is not empty
82
+ + asserts returns the element on #first
395
83
 
396
- require 'rake/testtask'
397
- Rake::TestTask.new(:test) do |test|
398
- test.libs << 'lib' << 'test'
399
- test.pattern = 'test/**/*_test.rb'
400
- test.verbose = false
401
- end
84
+ 3 passes, 0 failures, 0 errors in 0.000181 seconds
402
85
 
403
- Basically, it's like setting up any other test runner. Then, from the command line, you only need to run `rake` or `rake test`. Please make sure to remove all references to any other testing frameworks before running tests. For instance, do not require `test/unit`, `shoulda`, `minitest`, or anything else like it.
86
+ The various shorthands and macros are built in a way that ensures expressive and specific
87
+ feedback, e.g. the assertion
404
88
 
405
- <a name="sinatra"></a>
406
- ### With Sinatra
89
+ asserts(:full_name).matches(/^\w+ \w+$/)
407
90
 
408
- Riot definitely works with the latest Sinatra. I personally use it to run tests for [Chicago](http://github.com/thumblemonks/chicago) and [Slvu](http://github.com/jaknowlden/slvu). Setup is pretty easy and very much like getting your tests to run with Test::Unit. In a test helper file that gets loaded into all of your tests (that need it), enter the following:
91
+ yields the output
409
92
 
410
- require 'riot'
411
- class Riot::Situation
412
- include Rack::Test::Methods
413
- def app; @app; end
414
- end
93
+ !!!plain
94
+ + asserts #full_name matches /^\w+ \w+$/
415
95
 
416
- And then define a context (or many) for testing your Sinatra app. For instance:
417
96
 
418
- require 'test_helper'
419
-
420
- context 'Some App' do
421
- setup { @app = SomeApp }
422
-
423
- context "/index" do
424
- setup { get '/' }
425
- # ...
426
- end
427
- end
97
+ ### Testing Rack application
428
98
 
429
- Make sure to check out the Riot + Sinatra testing macros in Chicago. If you do happen to use Chicago, the above `test_helper.rb` setup can be compressed to the following while allowing the same test to work:
99
+ Rack applications can easily be tested using [Riot::Rack](http://github.com/dasch/riot-rack),
100
+ which integrates [Rack::Test](http://github.com/brynary/rack-test) into Riot.
430
101
 
431
102
  require 'riot'
432
- require 'chicago/riot'
103
+ require 'riot/rack'
433
104
 
434
- <a name="rails"></a>
435
- ### With Rails
436
-
437
- It's doubtful that Riot works with Rails very easily as Riot completely replaces Test::Unit. I haven't tried it yet, but intend to with my next new Rails project. Porting would probably take some time unless you only have a few test cases. Porting is made somewhat easier if you're already using Shoulda; you can replace the `TestCase` definition with a `context` of the same name as the class under test I suppose.
438
-
439
- <a name="extending"></a>
440
- ## Extending Riot with Macros
441
-
442
- To extend Riot, similar to how you would with Shoulda, you simply need to include your methods into the `Riot::Context` class. For example, let's say you wanted to add a helpful macro for asserting the response status of some HTTP result in Sinatra. You could do this easily by defining your macro like so:
443
-
444
- module Custom
445
- module Macros
446
- def asserts_response_status(expected)
447
- asserts("response status is #{expected}") do
448
- last_response.status
449
- end.equals(expected)
450
- end
451
- end # Macros
452
- end # Custom
453
- Riot::Context.instance_eval { include Custom::Macros }
454
-
455
- And then in your actual test, you might do the following:
456
-
457
- context 'Some App' do
458
- setup { @app = SomeApp }
459
-
460
- context "/index" do
461
- setup { get '/' }
462
- asserts_response_status 200
463
- end
464
- end
465
-
466
- **COMING SOON:** Riot will look into test/riot\_macros, but not today.
105
+ context "HelloWorldApp" do
106
+ # Specify your app using the #app helper. If you don't specify
107
+ # one, Riot::Rack will recursively look for a config.ru file.
108
+ app { HelloWorldApp }
467
109
 
468
- <a name="assertion-macros"></a>
469
- #### Assertion macros
110
+ # You can use all the Rack::Test helpers in the setup blocks.
111
+ setup { get '/' }
470
112
 
471
- If you want to add special macros to an Assertion, the process is really very easy. You simple need to define a class that extends `AssertionMacro` (or at least quacks like it), be sure to implement the `evaluate` instance method, and then register the macro.
472
-
473
- For instance, let's say you wanted to add a macro for verifying that the result of an assertion is the same `kind\_of` object as you would expect. You would define the macro like so:
474
-
475
- module Foo
476
- class KindOfMacro < Riot::AssertionMacro
477
- register :kind_of
113
+ # You can access the response directly.
114
+ asserts(:status).equals(200)
115
+ asserts(:body).equals("Hello, World!")
116
+ end
478
117
 
479
- def evaluate(actual, expected)
480
- if actual.kind_of?(expected)
481
- pass("is a kind of #{expected.inspect}")
482
- else
483
- fail("expected kind of #{expected}, not #{actual.inspect}")
484
- end
485
- end
486
- end # KindOfMacro
487
- end # Foo
488
118
 
489
- And in your context, you would use it like so:
119
+ ## Contributing
490
120
 
491
- context "example" do
492
- asserts("a hash is defined") { {:foo => 'bar'} }.kind_of(Hash)
493
- end
121
+ Riot is still in its infancy, so both the internal and external API may change radically.
122
+ That being said, we would love to hear any thoughts and ideas, and bug reports are always
123
+ welcome. We hang out in `#riot` on `irc.freenode.net`.
494
124
 
495
- If your assertion macro expects to be called only when an exception occurs, there's support for that, too. Check this:
125
+ The code is hosted on [GitHub](http://github.com), and can be fetched with
126
+ [Git](http://git-scm.com) by running:
496
127
 
497
- module Foo
498
- class RaisesMacro < Riot::AssertionMacro
499
- register :raises
500
- expects_exception! # THE IMPORTANT LINE
128
+ !!!plain
129
+ git clone git://github.com/thumblemonks/riot.git
501
130
 
502
- def evaluate(actual, expected)
503
- # ... pass/fail code
504
- end
505
- end # RaisesMacro
506
- end # Foo
507
131
 
132
+ ## License
508
133
 
509
- If you think you might want to chain assertions checks together, this won't work out the box. The reason for this is that your assertion macro should call out to pass or fail, which each return a signal that will be used by the reporter. You could conceivably write an assertion as a filter macro instead, that would return `self`, but I can't decide why you would do that yet (in theory it would work, though).
134
+ Riot is released under the MIT license. See {file:MIT-LICENSE}.