flunk 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Mysterious Trousers, LLC (http://www.mysterioustrousers.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,298 @@
1
+ Flunk
2
+ =====
3
+
4
+ A gem for testing a Ruby on Rails web APIs by simulating a client.
5
+
6
+
7
+ ### Installation
8
+
9
+ In your Gemfile, add this line:
10
+
11
+ gem "flunk"
12
+
13
+ ### Description
14
+
15
+ We write mostly JSON APIs using Rails, not your traditional web app, so we wanted a better way to test our JSON APIs. This is flunk.
16
+
17
+ ### Usage
18
+
19
+ In each test block you call a series of methods [`desc`, `path`, `method`, `username`, `password`, `body`, `status`, `assertions`] as necessary.
20
+
21
+ `desc`: In the future, a documentation generator will be added and this will be used to determine if the test should be documented as an API method.
22
+ `path`: The relative URL for the resource.
23
+ `method`: :get, :post, :put or :delete
24
+ `username`: For authentication using basic auth.
25
+ `password`: For authentication using basic auth.
26
+ `body`: The body of the request.
27
+ `status`: This method actually acts like an assertion. It is what the status of the response SHOULD be. An error will be thrown if it doesn't match.
28
+ `assertions`: A block of of assertions you call to verify the response was what it should have been.
29
+
30
+ Once you call `assertions`, the request is fired and a `result` method is available within the assertions block containing the response.
31
+
32
+ ### Example
33
+
34
+ It's your typical rails integration test, but inherits from Flunk:
35
+
36
+ class UsersTest < Flunk
37
+
38
+ setup do
39
+ @user = FactoryGirl.create(:user)
40
+ end
41
+
42
+ You write tests that SHOULD pass to test your app's basic functionality all works:
43
+
44
+ test "Create User" do
45
+ desc "Creating a new Langwich user."
46
+ path "signup"
47
+ method :post
48
+ body user: attrs = FactoryGirl.attributes_for(:user)
49
+ status :created
50
+ assertions {
51
+ assert_equal result[:name], attrs[:name]
52
+ assert_equal result[:username], attrs[:username]
53
+ assert_equal result[:email], attrs[:email]
54
+ assert_not_nil result[:api_token]
55
+ user = User.find_by_api_token result[:api_token]
56
+ assert_equal 1, user.languages.count
57
+ }
58
+ end
59
+
60
+ test "Log In" do
61
+ desc "Obtain a users API token by logging in with their username and password"
62
+ path "login"
63
+ method :get
64
+ body username: @user.username, password: @user.password
65
+ status :ok
66
+ assertions {
67
+ assert_not_nil result[:api_token]
68
+ }
69
+ end
70
+
71
+ test "Log In With Email" do
72
+ path "login"
73
+ method :get
74
+ body username: @user.email, password: @user.password
75
+ status :ok
76
+ assertions {
77
+ assert_not_nil result[:api_token]
78
+ }
79
+ end
80
+
81
+ test "Read User" do
82
+ desc "Read a users information."
83
+ path "account"
84
+ method :get
85
+ username @user.api_token
86
+ status :ok
87
+ end
88
+
89
+ test "Update User" do
90
+ desc "Update the username, e-mail, password and/or name"
91
+ path "account"
92
+ method :put
93
+ username @user.api_token
94
+ body user: { username: username = Faker::Internet.user_name }
95
+ status :ok
96
+ assertions {
97
+ assert_equal result[:username], username
98
+ }
99
+ end
100
+
101
+ test "Update E-mail" do
102
+ path "account"
103
+ method :put
104
+ username @user.api_token
105
+ body user: { email: email = Faker::Internet.email }
106
+ status :ok
107
+ assertions {
108
+ assert_equal result[:email], email
109
+ }
110
+ end
111
+
112
+ test "Update User Password" do
113
+ path "account"
114
+ method :put
115
+ username @user.api_token
116
+ body user: { password: Faker::Lorem.characters(10) }
117
+ status :ok
118
+ end
119
+
120
+ test "Update Name" do
121
+ path "account"
122
+ method :put
123
+ username @user.api_token
124
+ body user: { name: name = Faker::Name.first_name }
125
+ status :ok
126
+ assertions {
127
+ assert_equal result[:name], name
128
+ }
129
+ end
130
+
131
+ test "Delete User" do
132
+ path "account"
133
+ method :delete
134
+ username @user.api_token
135
+ status :ok
136
+ end
137
+
138
+
139
+
140
+ Then, write tests that SHOULDN'T pass to make sure your app rejects bad requests correctly/gracefully:
141
+
142
+
143
+ flunk "Create User", "Missing username" do
144
+ desc "Attempting to create a user without a username."
145
+ path "signup"
146
+ method :post
147
+ body user: FactoryGirl.attributes_for(:user, username: nil)
148
+ status :unprocessable_entity
149
+ end
150
+
151
+ flunk "Create User", "Username already taken" do
152
+ path "signup"
153
+ method :post
154
+ body user: FactoryGirl.attributes_for(:user, username: @user.username)
155
+ status :unprocessable_entity
156
+ end
157
+
158
+ flunk "Create User", "Invalid username" do
159
+ path "signup"
160
+ method :post
161
+ body user: FactoryGirl.attributes_for(:user, username: "a234$2aa" )
162
+ status :unprocessable_entity
163
+ end
164
+
165
+ flunk "Create User", "Missing e-mail" do
166
+ desc "Attempting to create a user without a e-mail."
167
+ path "signup"
168
+ method :post
169
+ body user: FactoryGirl.attributes_for(:user, email: nil)
170
+ status :unprocessable_entity
171
+ end
172
+
173
+ flunk "Create User", "E-mail already taken" do
174
+ desc "Attempting to create a user with an e-mail that's already taken."
175
+ path "signup"
176
+ method :post
177
+ body user: FactoryGirl.attributes_for(:user, email: @user.email)
178
+ status :unprocessable_entity
179
+ end
180
+
181
+ flunk "Create User", "Invalid e-mail" do
182
+ path "signup"
183
+ method :post
184
+ body user: FactoryGirl.attributes_for(:user, email: "aaaa@aakk")
185
+ status :unprocessable_entity
186
+ end
187
+
188
+ flunk "Create User", "Missing password" do
189
+ desc "Attempting to create a user without a password."
190
+ path "signup"
191
+ method :post
192
+ body user: FactoryGirl.attributes_for(:user, password: nil)
193
+ status :unprocessable_entity
194
+ end
195
+
196
+ flunk "Create User", "Missing name" do
197
+ path "signup"
198
+ method :post
199
+ body user: FactoryGirl.attributes_for(:user, name: nil)
200
+ status :unprocessable_entity
201
+ end
202
+
203
+
204
+
205
+
206
+ flunk "Log In", "No username" do
207
+ desc "Attempting to obtain an API token with the wrong password"
208
+ path "login"
209
+ method :get
210
+ body password: "a"
211
+ status :unauthorized
212
+ end
213
+
214
+ flunk "Log In", "Wrong password" do
215
+ desc "Attempting to obtain an API token with the wrong password"
216
+ path "login"
217
+ method :get
218
+ body username: @user.username, password: "a"
219
+ status :unauthorized
220
+ end
221
+
222
+
223
+
224
+
225
+ flunk "Read User", "Wrong API token" do
226
+ path "login"
227
+ method :get
228
+ username "a"
229
+ status :unauthorized
230
+ end
231
+
232
+
233
+
234
+
235
+ flunk "Update User", "Wrong password" do
236
+ path "account"
237
+ method :put
238
+ username "a"
239
+ body user: FactoryGirl.attributes_for(:user)
240
+ status :unauthorized
241
+ end
242
+
243
+ flunk "Update User", "Username already taken" do
244
+ path "account"
245
+ method :put
246
+ username @user.api_token
247
+ u = FactoryGirl.create(:user)
248
+ body user: { username: u.username }
249
+ status :unprocessable_entity
250
+ end
251
+
252
+ flunk "Update User", "Invalid username" do
253
+ path "account"
254
+ method :put
255
+ username @user.api_token
256
+ body user: { username: "a234$2aa" }
257
+ status :unprocessable_entity
258
+ end
259
+
260
+ flunk "Update User", "E-mail already taken" do
261
+ desc "Attempting to update a user with an e-mail that's already taken."
262
+ path "account"
263
+ method :put
264
+ username @user.api_token
265
+ u = FactoryGirl.create(:user)
266
+ body user: { email: u.email }
267
+ status :unprocessable_entity
268
+ end
269
+
270
+ flunk "Update User", "Invalid e-mail" do
271
+ desc "Attempting to update the user with an invalid e-mail"
272
+ path "account"
273
+ method :put
274
+ username @user.api_token
275
+ body user: { email: "aaaa@aakk" }
276
+ status :unprocessable_entity
277
+ end
278
+
279
+
280
+
281
+
282
+ flunk "Delete User", "Wrong password" do
283
+ path "account"
284
+ method :delete
285
+ username "a"
286
+ body user: FactoryGirl.attributes_for(:user)
287
+ status :unauthorized
288
+ end
289
+
290
+ end
291
+
292
+ ### Generator
293
+
294
+ To generate a flunk test:
295
+
296
+ rails g generate flunk_test User
297
+
298
+ This will create an integration test: test/integration/users_test.rb
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "flunk"
3
+ s.version = "0.0.1"
4
+ s.platform = Gem::Platform::RUBY
5
+ s.authors = ["Adam Kirk"]
6
+ s.email = %q{atomkirk@gmail.com}
7
+ s.homepage = %q{https://github.com/mysterioustrousers/flunk}
8
+ s.summary = %q{A gem for testing a Ruby on Rails web APIs by simulating a client.}
9
+ s.description = %q{A gem for testing a Ruby on Rails web APIs by simulating a client.}
10
+
11
+ s.files = `git ls-files`.split("\n").reject {|path| path =~ /\.gitignore$/ }
12
+ s.test_files =`git ls-files -- test/*`.split("\n")
13
+ s.require_paths = ["lib"]
14
+ end
@@ -0,0 +1,100 @@
1
+ class Flunk < ActionDispatch::IntegrationTest
2
+
3
+ def self.test(name, &block)
4
+ new_proc = Proc.new do
5
+ instance_eval(&block)
6
+ result
7
+ @assertions.call unless @assertions.nil?
8
+ end
9
+
10
+ super name, &new_proc
11
+ end
12
+
13
+ def self.flunk(action, failure_reason, &block)
14
+ test("FLUNKED: #{action} (#{failure_reason})", &block)
15
+ end
16
+
17
+ def result
18
+ if !@result_fetched
19
+ @result_fetched = true
20
+
21
+ if (@username || @password)
22
+ @headers ||= {}
23
+ @headers["HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64(@username.to_s + ":" + @password.to_s)}".strip
24
+ end
25
+
26
+ send @method, @path, @body, @headers
27
+
28
+ @response = response
29
+
30
+ assert_response @status
31
+
32
+ if response.body.length > 2
33
+ if response.content_type == 'application/json'
34
+ json = ActiveSupport::JSON.decode(response.body)
35
+ rec_symbolize( json )
36
+ @result = json
37
+ end
38
+ end
39
+ end
40
+
41
+ @result
42
+ end
43
+
44
+ def path(path)
45
+ @path = path
46
+ end
47
+
48
+ def method(method)
49
+ @method = method
50
+ end
51
+
52
+ def username(username)
53
+ @username = username
54
+ end
55
+
56
+ def password(password)
57
+ @password = password
58
+ end
59
+
60
+ def ssl(ssl)
61
+ @ssl = ssl
62
+ end
63
+
64
+ def body(body)
65
+ @body = body
66
+ end
67
+
68
+ def header(key, value)
69
+ @headers ||= {}
70
+ @headers[key] = value
71
+ end
72
+
73
+ def param(key, value)
74
+ @params ||= {}
75
+ @params[key] = value
76
+ end
77
+
78
+ def status(status)
79
+ @status = status
80
+ end
81
+
82
+ def desc(desc)
83
+ @desc = desc
84
+ end
85
+
86
+ def assertions(&block)
87
+ @assertions = block
88
+ end
89
+
90
+ def rec_symbolize(obj)
91
+ if obj.class == Hash
92
+ obj.symbolize_keys!
93
+ obj.map {|k,v| rec_symbolize(v) }
94
+ elsif obj.class == Array
95
+ obj.map {|v| rec_symbolize(v) }
96
+ end
97
+ nil
98
+ end
99
+
100
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ This generates an flunk rails integration test.
3
+
4
+ Example:
5
+ rails generate flunk_test Title
6
+
7
+ This will create:
8
+ test/integration/titles_test.rb
@@ -0,0 +1,7 @@
1
+ class FlunkTestGenerator < Rails::Generators::NamedBase
2
+ source_root File.expand_path('../templates', __FILE__)
3
+
4
+ def create_test_file
5
+ template "flunk_test.rb", "test/integration/#{file_name.pluralize}_test.rb"
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class <%= class_name.pluralize %>Test < Flunk
4
+
5
+ setup do
6
+ end
7
+
8
+ # Write tests that should succeed to make sure the required functionality works.
9
+ test "Test Title" do
10
+ desc "A description of the function this tests"
11
+ path "resource/:id"
12
+ method :get
13
+ username @user.username
14
+ password @user.password
15
+ status :ok
16
+ assertions {
17
+ assert_equal 2, 2
18
+ }
19
+ end
20
+
21
+
22
+ # Write a test that SHOULD fail to ensure your application handles bad requests gracefully.
23
+ flunk "Test Title", "Why it flunks" do
24
+ path "/resource/:id"
25
+ method :get
26
+ status :unauthorized
27
+ end
28
+
29
+ end
@@ -0,0 +1,2 @@
1
+ task flunk: ["test:integration"] do
2
+ end
@@ -0,0 +1,6 @@
1
+ require 'test/unit'
2
+ require 'flunk'
3
+
4
+ class FlunkTest < Test::Unit::TestCase
5
+
6
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flunk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Adam Kirk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-01 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A gem for testing a Ruby on Rails web APIs by simulating a client.
15
+ email: atomkirk@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - Rakefile
23
+ - flunk-0.0.1.gem
24
+ - flunk.gemspec
25
+ - lib/flunk.rb
26
+ - lib/generators/flunk_test/USAGE
27
+ - lib/generators/flunk_test/flunk_test_generator.rb
28
+ - lib/generators/flunk_test/templates/flunk_test.rb
29
+ - lib/tasks/flunk.rake
30
+ - test/test_flunk.rb
31
+ homepage: https://github.com/mysterioustrousers/flunk
32
+ licenses: []
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.24
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: A gem for testing a Ruby on Rails web APIs by simulating a client.
55
+ test_files:
56
+ - test/test_flunk.rb