itesttool 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/LICENSE.txt +8 -0
- data/README.md +263 -0
- data/Rakefile +7 -0
- data/lib/itesttool/custom_matchers.rb +168 -0
- data/lib/itesttool/version.rb +3 -0
- data/lib/itesttool.rb +156 -0
- metadata +187 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Copyright (c) 2013 Yohei Kariya
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
8
|
+
|
data/README.md
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
# itesttool
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/bati11/itesttool.png?branch=master)](https://travis-ci.org/bati11/itesttool)
|
4
|
+
|
5
|
+
WebアプリケーションのEnd-to-Endのテストを自動化するためのツール。
|
6
|
+
RSpecにユーティリティを追加して実現してます。
|
7
|
+
|
8
|
+
|
9
|
+
# Install
|
10
|
+
cloneしたらBundlerを使って必要なgemをインストールします。
|
11
|
+
~~~~~ {sh}
|
12
|
+
$ bundle install --path vendor/bundle
|
13
|
+
~~~~~
|
14
|
+
サンプルアプリケーションが起動します。
|
15
|
+
|
16
|
+
~~~~~ {sh}
|
17
|
+
$ bundle exec ruby sample/app.rb
|
18
|
+
~~~~~
|
19
|
+
|
20
|
+
以下のコマンドでサンプルに対するテストを実行します。
|
21
|
+
|
22
|
+
~~~~~ {sh}
|
23
|
+
$ bundle exec rspec
|
24
|
+
~~~~~
|
25
|
+
|
26
|
+
テストが通れば準備完了です。
|
27
|
+
|
28
|
+
|
29
|
+
# Usage
|
30
|
+
## GET リクエストを送信する
|
31
|
+
GET リクエスト送って、レスポンスコードを確認するには以下のようにします。
|
32
|
+
`_given` ブロックでテストの前提条件を書きます。`_given`は、単純にRSpecの`before`の別名です。
|
33
|
+
`_when` ブロックでGETリクエストを送ります。
|
34
|
+
`_then` ブロック内でres変数を使うことでレスポンスにアクセスできます。
|
35
|
+
resは、Net::HTTPResponseオブジェクトです。
|
36
|
+
|
37
|
+
~~~~~ {ruby}
|
38
|
+
describe 'send GET request' do
|
39
|
+
_given {
|
40
|
+
headers 'referer' => 'http://local.example.com',
|
41
|
+
}
|
42
|
+
_when { get 'http://localhost:4567/index' }
|
43
|
+
_then {
|
44
|
+
res.code.should eq '200'
|
45
|
+
}
|
46
|
+
end
|
47
|
+
~~~~~
|
48
|
+
|
49
|
+
## レスポンスを検証する
|
50
|
+
上の例にもありますが、ステータスコードは`res.code.should eq '200'`と書きます。
|
51
|
+
レスポンスボディは`res.body.should eq 'Hello world!'`というように書きます。
|
52
|
+
|
53
|
+
レスポンスボディが、JSON、XML、HTMLの場合はそれぞれ、JSONPath、XPath、CSSセレクタを用いて要素を検証できます。
|
54
|
+
JSONPath、XPathについては、下のサイトを参考にしてください。
|
55
|
+
[http://goessner.net/articles/JsonPath/](http://goessner.net/articles/JsonPath/)
|
56
|
+
|
57
|
+
また、配列に対する検証のために、以下のカスタムマッチャーを定義してます。
|
58
|
+
`all`は引数に、matcherを受け取ります。引数で受け取ったmatcherを配列の全要素に適用します。
|
59
|
+
`be_one_and`は引数に、matcherを受け取ります。まず配列の要素が1つであることを検証してから引数で受け取ったmatcherを要素に適用します。
|
60
|
+
`be_sorted`は配列の要素が、昇順もしくは降順で並んでいるかを検証します。
|
61
|
+
|
62
|
+
- `all`
|
63
|
+
- `be_one_and`
|
64
|
+
- `be_sorted`
|
65
|
+
|
66
|
+
|
67
|
+
### JSON
|
68
|
+
JSONPathを用いて、以下のように検証できます。
|
69
|
+
|
70
|
+
~~~~~ {ruby}
|
71
|
+
res['$.team'].should eq ['ABC']
|
72
|
+
res['$.members..name'].should eq ['Ichiro', 'Jiro', 'Saburo']
|
73
|
+
res['$.members..age'].should include 32
|
74
|
+
res['$.members[::]'].should have(3).items
|
75
|
+
res['$.members[::]'].should have_at_most(3).items
|
76
|
+
res['$.members[::]'].should have_at_least(1).items
|
77
|
+
res['$.members..name'].should all be_kind_of String
|
78
|
+
res['$.members..age'].should all be_kind_of Integer
|
79
|
+
res['$.members..age'].should all be > 11
|
80
|
+
res['$.members..age'].should all be >= 12
|
81
|
+
res['$.members..age'].should all be < 33
|
82
|
+
res['$.members..age'].should all be <= 32
|
83
|
+
res['$.members..age'].should be_sorted :desc
|
84
|
+
~~~~~
|
85
|
+
|
86
|
+
|
87
|
+
同じ要素を色々検証したい場合は、`select`を使ってブロック内に検証を書くと見やすいかも。
|
88
|
+
|
89
|
+
~~~~~ {ruby}
|
90
|
+
res.select('$.members..age') do |member_ages|
|
91
|
+
member_ages.should all be_kind_of Integer
|
92
|
+
member_ages.should all be > 11
|
93
|
+
member_ages.should all be >= 12
|
94
|
+
member_ages.should all be < 33
|
95
|
+
member_ages.should all be <= 32
|
96
|
+
member_ages.should be_sorted :desc
|
97
|
+
end
|
98
|
+
~~~~~
|
99
|
+
|
100
|
+
また、JSON schemaによる検証もできます。
|
101
|
+
json_schema/hello.js ファイルに以下のようなJSON schemaが記述します。
|
102
|
+
|
103
|
+
{
|
104
|
+
"type": "object",
|
105
|
+
"properties": {
|
106
|
+
"team": {"type": "string", "required": true},
|
107
|
+
"members": {
|
108
|
+
"type": "array",
|
109
|
+
"items": {
|
110
|
+
"type": "object",
|
111
|
+
"properties": {
|
112
|
+
"name": {"type": "string", "required": true},
|
113
|
+
"age": {"type": "integer", "required": true}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
`_then`ブロックに以下のように記述することで、レスポンスボディが上記のJSON schemaとマッチするかを検証できます。
|
121
|
+
|
122
|
+
~~~~~ {ruby}
|
123
|
+
res.body.should eq_schema_of 'json_schema/hello.json'
|
124
|
+
~~~~~
|
125
|
+
|
126
|
+
|
127
|
+
### XML
|
128
|
+
XPathを用いて以下のように検証できます。
|
129
|
+
|
130
|
+
~~~~~ {ruby}
|
131
|
+
res['/root/team/text()'].should eq ['ABC']
|
132
|
+
res['/root/members//name/text()'].should eq ['Ichiro', 'Jiro', 'Saburo']
|
133
|
+
res['/root/members//age/text()'].should include '32'
|
134
|
+
res['/root/members/*'].should have(3).items
|
135
|
+
res['/root/members/*'].should have_at_most(3).items
|
136
|
+
res['/root/members/*'].should have_at_least(1).items
|
137
|
+
res['/root/members//age/text()'].should all be > "11"
|
138
|
+
member_ages = res['/root/members//age/text()']
|
139
|
+
member_ages.should all be >= "10"
|
140
|
+
member_ages.should all be < "33"
|
141
|
+
member_ages.should all be <= "32"
|
142
|
+
member_ages.should be_sorted :desc
|
143
|
+
res['/root/members/member/@order'].should be_sorted :asc
|
144
|
+
~~~~~
|
145
|
+
|
146
|
+
|
147
|
+
### HTML
|
148
|
+
CSSセレクタを用いて以下のように検証できます。
|
149
|
+
|
150
|
+
~~~~~ {ruby}
|
151
|
+
res['title'].should eq ['Page Title!']
|
152
|
+
res['h1#team'].should eq ['ABC']
|
153
|
+
res['.member dd.name'].should eq ['Ichiro', 'Jiro', 'Saburo']
|
154
|
+
res['.member dd.age'].should include '32'
|
155
|
+
res['.member'].should have(3).items
|
156
|
+
res['.member'].should have_at_most(3).items
|
157
|
+
res['.member'].should have_at_least(1).items
|
158
|
+
res['.member dd.age'].should all be > "11"
|
159
|
+
member_ages = res['.member dd.age']
|
160
|
+
member_ages.should all be >= 10
|
161
|
+
member_ages.should all be < 33
|
162
|
+
member_ages.should all be <= 32
|
163
|
+
member_ages.should be_sorted :desc
|
164
|
+
~~~~~
|
165
|
+
|
166
|
+
|
167
|
+
## クエリパラメータを設定する
|
168
|
+
クエリパラメータを設定する方法は2通りあります。
|
169
|
+
1つ目が、単純にurlの末尾に"?"をつけてクエリパラメータを指定する方法です。
|
170
|
+
~~~~~ {ruby}
|
171
|
+
_when { get 'http://localhost:4567/index?night=true', as_text }
|
172
|
+
_then {
|
173
|
+
res.code.should eq '200'
|
174
|
+
}
|
175
|
+
~~~~~
|
176
|
+
|
177
|
+
2つ目が、`query`ヘルパー関数を使う方法です。
|
178
|
+
~~~~~ {ruby}
|
179
|
+
_when {
|
180
|
+
get 'http://localhost:4567/index',
|
181
|
+
as_text,
|
182
|
+
query('night' => 'true',
|
183
|
+
'times' => 3)
|
184
|
+
}
|
185
|
+
_then {
|
186
|
+
res.code.should eq '200'
|
187
|
+
}
|
188
|
+
~~~~~
|
189
|
+
|
190
|
+
|
191
|
+
## リクエストヘッダを設定する
|
192
|
+
リクエストヘッダの設定は、`_given`ブロックで、`headers`ヘルパー関数を呼び出して設定します。
|
193
|
+
`headers`関数に、ハッシュを渡して設定します。
|
194
|
+
~~~~~ {ruby}
|
195
|
+
_given {
|
196
|
+
headers 'referer' => 'http://local.example.com',
|
197
|
+
'user_agent' => 'itesttool'
|
198
|
+
}
|
199
|
+
_when { get 'http://localhost:4567/index.html', as_html }
|
200
|
+
_then {
|
201
|
+
res.code.should eq '200'
|
202
|
+
}
|
203
|
+
~~~~~
|
204
|
+
|
205
|
+
|
206
|
+
## POSTリクエストを送信する
|
207
|
+
POSTリクエストを送信する場合、`get`の代わりに`post`を使います。
|
208
|
+
第1引数に送信先URL、第2引数にリクエストボディ、第3引数にレスポンスのフォーマット、を指定します。
|
209
|
+
|
210
|
+
### formデータ
|
211
|
+
リクエストボディに、formデータを設定する場合は、`body_as_form`を使用します。
|
212
|
+
|
213
|
+
~~~~~ {ruby}
|
214
|
+
_when {
|
215
|
+
post 'http://localhost:4567/login',
|
216
|
+
body_as_form('nickname' => 'admin',
|
217
|
+
'password' => 'pass'),
|
218
|
+
res_is_json
|
219
|
+
}
|
220
|
+
_then {
|
221
|
+
res.code.should eq '200'
|
222
|
+
res['$.nickname'].should eq ['admin']
|
223
|
+
}
|
224
|
+
~~~~~
|
225
|
+
|
226
|
+
### JSON
|
227
|
+
リクエストボディに、JSONを設定する場合は、`body_as_json`を使用します。
|
228
|
+
|
229
|
+
~~~~~ {ruby}
|
230
|
+
_when {
|
231
|
+
post 'http://localhost:4567/echo',
|
232
|
+
body_as_json('name' => 'Shiro',
|
233
|
+
'age' => 2),
|
234
|
+
res_is_json
|
235
|
+
}
|
236
|
+
_then {
|
237
|
+
res.code.should eq '200'
|
238
|
+
res.body.should eq '{"name":"Shiro","age":2}'
|
239
|
+
}
|
240
|
+
~~~~~
|
241
|
+
|
242
|
+
単純に、`body`を使って直接文字列で設定することもできます。
|
243
|
+
|
244
|
+
~~~~~ {ruby}
|
245
|
+
_when {
|
246
|
+
post 'http://localhost:4567/echo',
|
247
|
+
body('{"name":"Shiro","age":2}'),
|
248
|
+
res_is_json
|
249
|
+
}
|
250
|
+
_then {
|
251
|
+
res.code.should eq '200'
|
252
|
+
res.body.should eq '{"name":"Shiro","age":2}'
|
253
|
+
}
|
254
|
+
~~~~~
|
255
|
+
|
256
|
+
## PUT, DELETEリクエスト
|
257
|
+
PUT, DELETEリクエストの場合は、`post`の代わりに`put`,`delete`を使ってください。
|
258
|
+
後は`post`の場合といっしょです。
|
259
|
+
|
260
|
+
|
261
|
+
# License
|
262
|
+
The MIT License. See LICENSE.txt
|
263
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'rubygems'
|
3
|
+
require 'json-schema'
|
4
|
+
|
5
|
+
def eq_schema_of(schema_file)
|
6
|
+
EqSchemaOf.new(schema_file)
|
7
|
+
end
|
8
|
+
|
9
|
+
class EqSchemaOf
|
10
|
+
def initialize(schema_file)
|
11
|
+
@schema_file = schema_file
|
12
|
+
end
|
13
|
+
def matches? (body)
|
14
|
+
@body = body
|
15
|
+
@msg = ""
|
16
|
+
begin
|
17
|
+
JSON::Validator.validate!(@schema_file, body)
|
18
|
+
true
|
19
|
+
rescue JSON::Schema::ValidationError
|
20
|
+
@msg = $!.message
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def failure_message_for_should
|
26
|
+
<<"MSG"
|
27
|
+
|
28
|
+
Invalid response body on "#{@schema_file}".
|
29
|
+
#{@msg}
|
30
|
+
|
31
|
+
Body is
|
32
|
+
====================
|
33
|
+
#{@body}
|
34
|
+
|
35
|
+
#{@schema_file} is
|
36
|
+
====================
|
37
|
+
#{File.open(@schema_file).read}
|
38
|
+
|
39
|
+
MSG
|
40
|
+
end
|
41
|
+
|
42
|
+
def failure_message_for_should_not
|
43
|
+
"\nValid response body on \"#{@schema_file}\".\n\n"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def be_sorted(order)
|
49
|
+
BeSorted.new(order)
|
50
|
+
end
|
51
|
+
|
52
|
+
class BeSorted
|
53
|
+
def initialize(order)
|
54
|
+
@order = order
|
55
|
+
end
|
56
|
+
def matches?(list)
|
57
|
+
@list = list
|
58
|
+
type = list.first.class
|
59
|
+
unless list.all?{|x| x.class == type }
|
60
|
+
@not_aligned = true
|
61
|
+
false
|
62
|
+
else
|
63
|
+
sorted_list = list.sort
|
64
|
+
if @order == :asc
|
65
|
+
list == sorted_list
|
66
|
+
elsif @order == :desc
|
67
|
+
list == sorted_list.reverse
|
68
|
+
else
|
69
|
+
@order_invalid = true
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def failure_message_for_should
|
76
|
+
if @not_aligned
|
77
|
+
"expected #{@list.inspect} type is not available."
|
78
|
+
elsif @order_invalid
|
79
|
+
"specified order is invalid. valid order in [:asc, :desc]"
|
80
|
+
else
|
81
|
+
"expected #{@list.inspect} to be sorted #{@order}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def all(meta)
|
88
|
+
All.new(meta)
|
89
|
+
end
|
90
|
+
|
91
|
+
class All
|
92
|
+
def initialize(matcher)
|
93
|
+
@matcher = matcher
|
94
|
+
end
|
95
|
+
|
96
|
+
def matches?(rows)
|
97
|
+
rows.each_with_index do |i, j|
|
98
|
+
@elem = j
|
99
|
+
unless @matcher.matches? i
|
100
|
+
return false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
return true
|
104
|
+
end
|
105
|
+
|
106
|
+
def failure_message_for_should
|
107
|
+
"at[#{@elem}] #{@matcher.failure_message_for_should}"
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def be_one_and(meta)
|
114
|
+
BeOneAnd.new(meta)
|
115
|
+
end
|
116
|
+
|
117
|
+
class BeOneAnd
|
118
|
+
def initialize(matcher)
|
119
|
+
@matcher = matcher
|
120
|
+
end
|
121
|
+
|
122
|
+
def matches?(rows)
|
123
|
+
@have_error = false
|
124
|
+
@have = RSpec::Matchers::BuiltIn::Have.new(1).items
|
125
|
+
unless @have.matches? rows then
|
126
|
+
@have_error = true
|
127
|
+
return false;
|
128
|
+
end
|
129
|
+
@matcher.matches? rows[0]
|
130
|
+
end
|
131
|
+
|
132
|
+
def failure_message_for_should
|
133
|
+
if @have_error
|
134
|
+
@have.failure_message_for_should
|
135
|
+
else
|
136
|
+
@matcher.failure_message_for_should
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
def include_with(key, values)
|
143
|
+
IncludeWith.new(key, values)
|
144
|
+
end
|
145
|
+
|
146
|
+
class IncludeWith
|
147
|
+
def initialize(key, values)
|
148
|
+
@key = key
|
149
|
+
@values = values
|
150
|
+
end
|
151
|
+
def matches?(rows)
|
152
|
+
@rows = rows
|
153
|
+
list = rows.map{|x| x[@key]}
|
154
|
+
Set[*list] == Set[*@values]
|
155
|
+
end
|
156
|
+
|
157
|
+
def failure_message_for_should
|
158
|
+
str = @values.map{|x| "#{@key} => #{x}"}.join(" and ")
|
159
|
+
"expected #{@rows.inspect} to include #{str}"
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
def msg_of_type_invalid
|
164
|
+
str = @values.map{|x| "#{@key} => #{x}"}.join(" and ")
|
165
|
+
"expected not #{@rows.inspect} to include #{str}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
data/lib/itesttool.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'rubygems'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'jsonpath'
|
7
|
+
require 'nokogiri'
|
8
|
+
require "itesttool/version"
|
9
|
+
require "itesttool/custom_matchers"
|
10
|
+
|
11
|
+
def _given(&b) before(:each, &b) end
|
12
|
+
def _when(&b) let(:res, &b) end
|
13
|
+
def _then(&b) it(&b) end
|
14
|
+
|
15
|
+
module ItestHelpers
|
16
|
+
|
17
|
+
def as_text() "text" end
|
18
|
+
def as_json() "json" end
|
19
|
+
def as_xml() "xml" end
|
20
|
+
def as_html() "html" end
|
21
|
+
|
22
|
+
alias res_is_json as_json
|
23
|
+
alias res_is_xml as_xml
|
24
|
+
alias res_is_html as_html
|
25
|
+
|
26
|
+
def headers(h = {})
|
27
|
+
@headers = h
|
28
|
+
end
|
29
|
+
|
30
|
+
def query(h = {})
|
31
|
+
h.map{ |k, v| URI.encode(k) + "=" + URI.encode(v.to_s) }.join("&")
|
32
|
+
end
|
33
|
+
|
34
|
+
def body(data = "")
|
35
|
+
{:body => data}
|
36
|
+
end
|
37
|
+
def body_as_form(data = {})
|
38
|
+
{:form => data}
|
39
|
+
end
|
40
|
+
def body_as_json(data = {})
|
41
|
+
{:json => data}
|
42
|
+
end
|
43
|
+
|
44
|
+
def get(url, res_format="text", query="")
|
45
|
+
url_obj = URI.parse(url)
|
46
|
+
res = Net::HTTP.start(url_obj.host, url_obj.port) {|http|
|
47
|
+
queries = []
|
48
|
+
queries.push(query) unless query.empty?
|
49
|
+
queries.push(url_obj.query) unless url_obj.query.nil?
|
50
|
+
path_with_query =
|
51
|
+
if queries.empty?
|
52
|
+
url_obj.path
|
53
|
+
else
|
54
|
+
url_obj.path + "?" + queries.join("&")
|
55
|
+
end
|
56
|
+
request = Net::HTTP::Get.new(path_with_query)
|
57
|
+
add_headers(request)
|
58
|
+
http.request(request)
|
59
|
+
}
|
60
|
+
decorate_response(res, "GET", url, res_format)
|
61
|
+
end
|
62
|
+
|
63
|
+
def post(url, data, res_format)
|
64
|
+
url_obj = URI.parse(url)
|
65
|
+
res = Net::HTTP.start(url_obj.host, url_obj.port) {|http|
|
66
|
+
request = Net::HTTP::Post.new(url_obj.path)
|
67
|
+
setup(request, data)
|
68
|
+
http.request(request)
|
69
|
+
}
|
70
|
+
decorate_response(res, "POST", url, res_format)
|
71
|
+
end
|
72
|
+
|
73
|
+
def put(url, data, res_format)
|
74
|
+
url_obj = URI.parse(url)
|
75
|
+
res = Net::HTTP.start(url_obj.host, url_obj.port) {|http|
|
76
|
+
request = Net::HTTP::Put.new(url_obj.path)
|
77
|
+
setup(request, data)
|
78
|
+
http.request(request)
|
79
|
+
}
|
80
|
+
decorate_response(res, "PUT", url, res_format)
|
81
|
+
end
|
82
|
+
|
83
|
+
def delete(url, data, res_format)
|
84
|
+
url_obj = URI.parse(url)
|
85
|
+
res = Net::HTTP.start(url_obj.host, url_obj.port) {|http|
|
86
|
+
request = Net::HTTP::DELETE.new(url_obj.path)
|
87
|
+
setup(request, data)
|
88
|
+
http.request(request)
|
89
|
+
}
|
90
|
+
decorate_response(res, "DELETE", url, res_format)
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
def setup(request, data)
|
95
|
+
set_body(request, data)
|
96
|
+
add_headers(request)
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_headers(request)
|
100
|
+
if @headers then @headers.each{|k, v| request.add_field k, v} end
|
101
|
+
end
|
102
|
+
|
103
|
+
def set_body(request, data)
|
104
|
+
if data.include? :form
|
105
|
+
set_form_data(request, data[:form])
|
106
|
+
elsif data.include? :json
|
107
|
+
request.body = JSON.generate(data[:json])
|
108
|
+
else
|
109
|
+
request.body = data[:body]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_form_data(request, params, sep = '&')
|
114
|
+
request.body = params.map {|k, v| encode_kvpair(k, v) }.flatten.join(sep)
|
115
|
+
request.content_type = 'application/x-www-form-urlencoded'
|
116
|
+
end
|
117
|
+
|
118
|
+
def encode_kvpair(k, vs)
|
119
|
+
Array(vs).map {|v| "#{URI::encode(k.to_s)}=#{URI::encode(v.to_s)}" }
|
120
|
+
end
|
121
|
+
|
122
|
+
def decorate_response(res, method, url, res_format)
|
123
|
+
class << res
|
124
|
+
attr_accessor :url, :res_format, :method
|
125
|
+
def [](path)
|
126
|
+
select(path)
|
127
|
+
end
|
128
|
+
def select(path, &block)
|
129
|
+
result =
|
130
|
+
if res_format && res_format == "xml"
|
131
|
+
Nokogiri::XML(body).xpath(path).map{|x| x.text}
|
132
|
+
elsif res_format && res_format == "html"
|
133
|
+
Nokogiri::HTML(body).css(path).map{|x| x.text}
|
134
|
+
elsif res_format && res_format == "json"
|
135
|
+
JsonPath.on(body, path)
|
136
|
+
end
|
137
|
+
block.call(result) unless block.nil?
|
138
|
+
result
|
139
|
+
end
|
140
|
+
def to_s
|
141
|
+
method + " " + url
|
142
|
+
end
|
143
|
+
end
|
144
|
+
res.url = url
|
145
|
+
res.res_format = res_format
|
146
|
+
res.method = method
|
147
|
+
res
|
148
|
+
end
|
149
|
+
|
150
|
+
module_function :get, :post, :add_headers, :decorate_response
|
151
|
+
end
|
152
|
+
|
153
|
+
RSpec.configure do |c|
|
154
|
+
c.include ItestHelpers
|
155
|
+
end
|
156
|
+
|
metadata
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: itesttool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- bati11
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-01-26 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.14'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.14'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: json-schema
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.2'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.2'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: json
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.8.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: jsonpath
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.5.5
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.5.5
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: nokogiri
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.6.1
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.6.1
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: sinatra
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '1.4'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1.4'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: bundler
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.3'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.3'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rake
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
description: End-to-End Test tool for web api.
|
143
|
+
email:
|
144
|
+
- mail.bati11@gmail.com
|
145
|
+
executables: []
|
146
|
+
extensions: []
|
147
|
+
extra_rdoc_files: []
|
148
|
+
files:
|
149
|
+
- lib/itesttool.rb
|
150
|
+
- lib/itesttool/version.rb
|
151
|
+
- lib/itesttool/custom_matchers.rb
|
152
|
+
- Rakefile
|
153
|
+
- Gemfile
|
154
|
+
- README.md
|
155
|
+
- LICENSE.txt
|
156
|
+
homepage: ''
|
157
|
+
licenses:
|
158
|
+
- MIT
|
159
|
+
post_install_message:
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
none: false
|
165
|
+
requirements:
|
166
|
+
- - ! '>='
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
segments:
|
170
|
+
- 0
|
171
|
+
hash: 242860858589185526
|
172
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
|
+
none: false
|
174
|
+
requirements:
|
175
|
+
- - ! '>='
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
segments:
|
179
|
+
- 0
|
180
|
+
hash: 242860858589185526
|
181
|
+
requirements: []
|
182
|
+
rubyforge_project:
|
183
|
+
rubygems_version: 1.8.23
|
184
|
+
signing_key:
|
185
|
+
specification_version: 3
|
186
|
+
summary: End-to-End Test tool for web api.
|
187
|
+
test_files: []
|