flunk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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