protest 0.4.2 → 0.5.0

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.
@@ -1,237 +0,0 @@
1
- = Protest, the simplicity rebel test framework
2
-
3
- require "protest"
4
-
5
- Protest.describe("A user") do
6
- setup do
7
- @user = User.new(:name => "John Doe", :email => "john@example.org")
8
- end
9
-
10
- it "has a name" do
11
- assert_equal "John Doe", @user.name
12
- end
13
-
14
- it "has an email" do
15
- assert_equal "john@example.org", @user.email
16
- end
17
- end
18
-
19
- Protest is a small, simple, and easy-to-extend testing framework for ruby. It
20
- was written as a replacement for Test::Unit, given how awful its code is, and
21
- how difficult it is to extend in order to add new features.
22
-
23
- I believe in minimalistic software, which is easily understood, easy to test,
24
- and specially, easy to extend for third parties. That's where I'm aiming with
25
- Protest.
26
-
27
- == Get it
28
-
29
- gem install protest
30
-
31
- Or
32
-
33
- rip install git://github.com/matflores/protest.git v0.4.0
34
-
35
- == Setup and teardown
36
-
37
- If you need to run code before or after each test, declare a +setup+ or
38
- +teardown+ block (respectively.)
39
-
40
- Protest.context("A user") do
41
- setup do # this runs before each test
42
- @user = User.create(:name => "John")
43
- end
44
-
45
- teardown do # this runs after each test
46
- @user.destroy
47
- end
48
- end
49
-
50
- +setup+ and +teardown+ blocks are evaluated in the same context as your test,
51
- which means any instance variables defined in any of them are available in the
52
- rest. Both methods are aliased for your comfort as before and after respectively.
53
-
54
- You can also use +global_setup+ and +global_teardown+ to run code only once per
55
- test case. +global_setup+ blocks will run once before the first test is run, and
56
- +global_teardown+ will run after all the tests have been run.
57
-
58
- These methods, however, are dangerous, and should be used with caution, as
59
- they might introduce dependencies between your tests if you don't write
60
- your tests properly. Make sure that any state modified by code run in a
61
- +global_setup+ or +global_teardown+ isn't changed in any of your tests.
62
-
63
- Also, you should be aware that the code of +global_setup+ and +global_teardown+
64
- blocks isn't evaluated in the same context as your tests and normal
65
- +setup+/+teardown+ blocks are, so you can't share instance variables between
66
- them.
67
-
68
- == Nested contexts
69
-
70
- Break down your test into logical chunks with nested contexts:
71
-
72
- Protest.describe("A user") do
73
- setup do
74
- @user = User.make
75
- end
76
-
77
- context "when validating" do
78
- it "validates name" do
79
- @user.name = nil
80
- assert !@user.valid?
81
- end
82
-
83
- # etc, etc
84
- end
85
-
86
- context "doing something else" do
87
- # you get the idea
88
- end
89
- end
90
-
91
- Any +setup+ or +teardown+ blocks you defined in a context will run in that
92
- context and in _any_ other context nested in it.
93
-
94
- == Pending tests
95
-
96
- There are two ways of marking a test as pending. You can declare a test with no
97
- body:
98
-
99
- Protest.context("Some tests") do
100
- test "this test will be marked as pending"
101
-
102
- test "this tests is also pending"
103
-
104
- test "this test isn't pending" do
105
- assert true
106
- end
107
- end
108
-
109
- Or you can call the +pending+ method from inside your test.
110
-
111
- Protest.context("Some tests") do
112
- test "this test is pending" do
113
- pending "oops, this doesn't work"
114
- assert false
115
- end
116
- end
117
-
118
- == Custom assertions
119
-
120
- Previous versions of Protest used to bundle all the assertions defined in
121
- Test::Unit, but that has changed and now Protest includes just three basic
122
- assertion methods:
123
-
124
- - assert
125
- - assert_equal
126
- - assert_raise
127
-
128
- If you want to add assertions, just define methods that rely on +assert+.
129
- This method takes a boolean and an optional error message as arguments, and
130
- the assertion is considered to fail if the boolean evaluates to neither
131
- +false+ nor +nil+.
132
-
133
- For example:
134
-
135
- module AwesomenessAssertions
136
- def assert_awesomeness(object)
137
- assert object.awesome?, "#{object.inspect} is not awesome enough"
138
- end
139
- end
140
-
141
- class Protest::TestCase
142
- include AwesomenessAssertions
143
- end
144
-
145
- You could also define rspec-like matchers if you like that style. See
146
- <tt>matchers.rb</tt> in the examples directory for an example.
147
-
148
- == Reports
149
-
150
- Protest can report the output of a test suite in many ways. The library ships
151
- with a <tt>:progress</tt> report, and a <tt>:documentation</tt> report,
152
- <tt>:progress</tt> being the default.
153
-
154
- === Progress report
155
-
156
- This is the default option, but you can force this by calling
157
- <tt>Protest.report_with(:progress)</tt>.
158
-
159
- The progress report will output the "classic" Test::Unit output of periods for
160
- passing tests, "F" for failing assertions, "E" for unrescued exceptions, and
161
- "P" for pending tests, in full color.
162
-
163
- === Documentation report
164
-
165
- Use this report by calling <tt>Protest.report_with(:documentation)</tt>
166
-
167
- For each testcase in your suite, this will output the description of the test
168
- case (whatever you provide TestCase.context), followed by the name of each test
169
- in that context, one per line. For example:
170
-
171
- Protest.context "A user" do
172
- test "has a name"
173
- test "has an email"
174
-
175
- context "validations" do
176
- test "ensure the email can't be blank"
177
- end
178
- end
179
-
180
- Will output, when run with the <tt>:documentation</tt> report:
181
-
182
- A user
183
- - has a name (Not Yet Implemented)
184
- - has an email (Not Yet Implemented)
185
-
186
- A user validations
187
- - ensure the email can't be blank (Not Yet Implemented)
188
-
189
- (The 'Not Yet Implemented' messages are because the tests have no body. See
190
- "Pending tests", above.)
191
-
192
- This is similar to the specdoc runner in rspec[http://rspec.info].
193
-
194
- === Summary report
195
-
196
- Use this report by calling <tt>Protest.report_with(:summary)</tt>
197
-
198
- Will output a brief summary with the total number of tests, assertions, passed
199
- tests, pending tests, failed tests and errors.
200
-
201
- === Stories report
202
-
203
- Use this report by calling <tt>Protest.report_with(:stories)</tt>
204
-
205
- This report is based on Citrusbyte's Stories[http://github.com/citrusbyte/stories],
206
- by Damian Janowski and Michel Martens.
207
-
208
- === Turn report
209
-
210
- Use this report by calling <tt>Protest.report_with(:turn)</tt>
211
-
212
- This report displays each test on a separate line with failures being displayed
213
- immediately instead of at the end of the tests.
214
-
215
- You might find this useful when running a large test suite, as it can be very
216
- frustrating to see a failure (....F...) and then have to wait until all the
217
- tests finish before you can see what the exact failure was.
218
-
219
- This report is based on the output displayed by TURN[http://github.com/TwP/turn],
220
- Test::Unit Reporter (New) by Tim Pease.
221
-
222
- === Defining your own reports
223
-
224
- This is really, really easy. All you need to do is subclass Report, and
225
- register your subclass by calling +Protest.add_report+. See the
226
- documentation for details, or take a look at the source code for
227
- Protest::Reports::Progress and Protest::Reports::Documentation.
228
-
229
- == Using Rails?
230
-
231
- If you are using Rails you may want to take a look at http://github.com/matflores/protest-rails.
232
-
233
- == Legal
234
-
235
- Maintainer:: Matías Flores — http://matflores.com
236
- Author:: Nicolás Sanguinetti — http://nicolassanguinetti.info
237
- License:: MIT (see bundled LICENSE file for more info)
@@ -1,61 +0,0 @@
1
- module Protest
2
- # This report is based on Citrusbyte's Stories[http://github.com/citrusbyte/stories],
3
- # by Damian Janowski and Michel Martens.
4
- class Reports::Stories < Report
5
- include Utils::Summaries
6
- include Utils::ColorfulOutput
7
-
8
- attr_reader :stream #:nodoc:
9
-
10
- # Set the stream where the report will be written to. STDOUT by default.
11
- def initialize(stream=STDOUT)
12
- @stream = stream
13
- end
14
-
15
- on :pass do |report, pass|
16
- report.print ".", :passed
17
- end
18
-
19
- on :pending do |report, pending|
20
- report.print "P", :pending
21
- end
22
-
23
- on :failure do |report, failure|
24
- report.print "F", :failed
25
- end
26
-
27
- on :error do |report, error|
28
- report.print "E", :errored
29
- end
30
-
31
- on :end do |report|
32
- report.puts
33
-
34
- Stories.all.values.to_a.each_with_index do |story,i|
35
- report.puts "- #{story.name}"
36
-
37
- story.scenarios.each do |scenario|
38
- report.puts " #{scenario.name}"
39
-
40
- unless scenario.steps.empty? && scenario.assertions.empty?
41
- scenario.steps.each do |step|
42
- report.puts " #{step}"
43
- end
44
-
45
- scenario.assertions.each do |assertion|
46
- report.puts " #{assertion}"
47
- end
48
-
49
- report.puts
50
- end
51
- end
52
-
53
- report.puts unless i + 1 == Stories.all.values.size
54
- end
55
-
56
- report.puts "%d stories, %d scenarios" % [Stories.all.values.size, Stories.all.values.inject(0) {|total,s| total + s.scenarios.size }]
57
- end
58
- end
59
-
60
- add_report :stories, Reports::Stories
61
- end
@@ -1,72 +0,0 @@
1
- require "rubygems"
2
-
3
- gem "prawn", "~> 0.4"
4
- require "prawn"
5
-
6
- module Protest
7
- # This report is based on Citrusbyte's Stories[http://github.com/citrusbyte/stories],
8
- # by Damian Janowski and Michel Martens.
9
- module Reports
10
- class Stories::PDF < Report
11
- include Utils::Summaries
12
- include Utils::ColorfulOutput
13
-
14
- attr_reader :stream #:nodoc:
15
-
16
- # Set the stream where the report will be written to. STDOUT by default.
17
- def initialize(stream=STDOUT)
18
- @stream = stream
19
- end
20
-
21
- def render_header(pdf)
22
- end
23
-
24
- def render_many(pdf, elements)
25
- elements.each do |el|
26
- pdf.text el.to_s
27
- end
28
- end
29
-
30
- on :end do |report|
31
- Prawn::Document.generate("stories.pdf", :page_size => "A4") do |pdf|
32
- report.render_header(pdf)
33
-
34
- pdf.text "User Acceptance Tests", :size => 20, :style => :bold
35
-
36
- pdf.move_down(15)
37
-
38
- Protest::Stories.all.values.each do |story|
39
- pdf.text story.name, :style => :bold
40
-
41
- story.scenarios.each_with_index do |scenario,i|
42
- scenario_leading = 15
43
-
44
- pdf.span(pdf.bounds.width - scenario_leading, :position => scenario_leading) do
45
- pdf.text "— #{scenario.name}"
46
-
47
- pdf.fill_color "666666"
48
-
49
- unless scenario.steps.empty? && scenario.assertions.empty?
50
- pdf.span(pdf.bounds.width - 30, :position => 30) do
51
- pdf.font_size(9) do
52
- report.render_many(pdf, scenario.steps)
53
- report.render_many(pdf, scenario.assertions)
54
- end
55
- end
56
- end
57
-
58
- pdf.move_down(5) unless i + 1 == story.scenarios.size
59
-
60
- pdf.fill_color "000000"
61
- end
62
- end
63
-
64
- pdf.move_down(10)
65
- end
66
- end
67
- end
68
- end
69
- end
70
-
71
- add_report :stories_pdf, Reports::Stories::PDF
72
- end
@@ -1,130 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Protest
4
- def self.story(description, &block)
5
- context(description) do
6
- Protest::Stories.all[self] = Protest::Stories::Story.new(description)
7
- class_eval(&block) if block_given?
8
- end
9
- end
10
-
11
- def self.scenario(name, &block)
12
- scenario = Protest::Stories::Scenario.new(name)
13
-
14
- Protest::Stories.all[self].scenarios << scenario
15
-
16
- test(name) do
17
- @scenario = scenario
18
- instance_eval(&block)
19
- end
20
- end
21
-
22
- module Stories
23
- def self.all
24
- @all ||= {}
25
- end
26
-
27
- module TestCase
28
- def self.included(base)
29
- class << base
30
- def story(description, &block)
31
- context(description) do
32
- Protest::Stories.all[self] = Protest::Stories::Story.new(description)
33
- class_eval(&block) if block_given?
34
- end
35
- end
36
-
37
- def scenario(name, &block)
38
- scenario = Protest::Stories::Scenario.new(name)
39
-
40
- Protest::Stories.all[self].scenarios << scenario
41
-
42
- test(name) do
43
- @scenario = scenario
44
- instance_eval(&block)
45
- end
46
- end
47
- end
48
- end
49
- end
50
-
51
- class Story
52
- attr_accessor :name, :scenarios
53
-
54
- def initialize(name)
55
- @name = name
56
- @scenarios = []
57
- end
58
- end
59
-
60
- class Scenario
61
- attr_accessor :name, :steps, :assertions
62
-
63
- def initialize(name)
64
- @name = name
65
- @steps = []
66
- @assertions = []
67
- end
68
- end
69
-
70
- module Methods
71
- def report(text, &block)
72
- @scenario.steps << text
73
- silent(&block) if block_given?
74
- end
75
-
76
- def silent(&block)
77
- scenario, @scenario = @scenario, Stories::Scenario.new("#{@scenario.name} (Silent)")
78
-
79
- begin
80
- block.call
81
- ensure
82
- @scenario = scenario
83
- end
84
- end
85
- end
86
-
87
- module Webrat
88
- def report_for(action, &block)
89
- define_method(action) do |*args|
90
- @scenario.steps << block.call(*args)
91
- super(*args)
92
- end
93
- end
94
- module_function :report_for
95
-
96
- report_for :click_link do |name|
97
- "Click #{quote(name)}"
98
- end
99
-
100
- report_for :click_button do |name|
101
- "Click #{quote(name)}"
102
- end
103
-
104
- report_for :fill_in do |name, opts|
105
- "Fill in #{quote(name)} with #{quote(opts[:with])}"
106
- end
107
-
108
- report_for :visit do |page|
109
- "Go to #{quote(page)}"
110
- end
111
-
112
- report_for :check do |name|
113
- "Check #{quote(name)}"
114
- end
115
-
116
- report_for :assert_contain do |text|
117
- "I should see #{quote(text)}"
118
- end
119
-
120
- def quote(text)
121
- "“#{text}”"
122
- end
123
- module_function :quote
124
- end
125
- end
126
-
127
- Protest::TestCase.send(:include, Protest::Stories::TestCase)
128
- Protest::TestCase.send(:include, Protest::Stories::Methods)
129
- Protest::TestCase.send(:include, Protest::Stories::Webrat)
130
- end