fake_mechanize 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +54 -1
- data/Rakefile +13 -4
- data/VERSION +1 -1
- data/examples/tiny_url.rb +46 -0
- data/lib/fake_mechanize.rb +55 -1
- data/lib/fake_mechanize/agent.rb +44 -14
- data/lib/fake_mechanize/error_request.rb +14 -2
- data/lib/fake_mechanize/request.rb +28 -3
- data/lib/fake_mechanize/responder.rb +3 -0
- metadata +8 -4
data/README.rdoc
CHANGED
@@ -1,12 +1,65 @@
|
|
1
1
|
= fake-mechanize
|
2
2
|
|
3
3
|
== DESCRIPTION
|
4
|
-
|
4
|
+
FakeMechanize provides methods and classes to write offline tests for applications which relies on Mechanize.
|
5
|
+
It replace Mechanize and emulate an agent which aim to act like a real Mechanize Agent.
|
6
|
+
Fake agent accepts options to define queries and their answers.
|
5
7
|
|
6
8
|
== SYNOPSIS
|
7
9
|
=== Options
|
8
10
|
=== Types
|
9
11
|
=== Examples
|
12
|
+
* Simple examples to test a basic api
|
13
|
+
|
14
|
+
# Initialize a fake agent
|
15
|
+
@http_agent = FakeMechanize::Agent.new
|
16
|
+
|
17
|
+
# Create answers and their params
|
18
|
+
@http_agent.respond_to do |mock|
|
19
|
+
|
20
|
+
# Answers to get queries to http://api.example.com/users/count?group=students
|
21
|
+
# with the string "42"
|
22
|
+
mock.get :uri => "http://api.example.com/users/count",
|
23
|
+
:parameters => {:group => "students"},
|
24
|
+
:body => "42"
|
25
|
+
|
26
|
+
# Answers to post queries to http://api.example.com/users/3/activate
|
27
|
+
# with the string "true"
|
28
|
+
mock.post :uri => "http://api.example.com/users/3/activate",
|
29
|
+
:body => "true"
|
30
|
+
|
31
|
+
# Answers to post queries to http://api.example.com/users/authentify
|
32
|
+
# with the string "Qt5c1HWwCXDhKskMrBqMdQ".
|
33
|
+
# This example could be an authentication process
|
34
|
+
mock.post :uri => "http://api.example.com/users/authentify",
|
35
|
+
:parameters => {:Email => 'jack@bauer.com', :Passwd => 'secure'},
|
36
|
+
:body => "Qt5c1HWwCXDhKskMrBqMdQ"
|
37
|
+
|
38
|
+
# Will reply with an http error code of 403 with no body if the post query
|
39
|
+
# to http://api.example.com/users/authentify does not have specified parameters.
|
40
|
+
mock.error :uri => "http://api.example.com/users/authentify",
|
41
|
+
:params_not_equal => {:Email => 'jack@bauer.com', :Passwd => 'secure'},
|
42
|
+
:method => :post,
|
43
|
+
:status => 403
|
44
|
+
end
|
45
|
+
|
46
|
+
# Now you can use this agent like a real one
|
47
|
+
r = mock.get("http://api.example.com/users/count", :group => "students")
|
48
|
+
# => WWW::Mechanize::File
|
49
|
+
r.body # => "42"
|
50
|
+
|
51
|
+
# Posting
|
52
|
+
r = mock.post("http://api.example.com/users/authentify",
|
53
|
+
:Email => "jack@bauer.com", :Passwd => "secure")
|
54
|
+
r.status # => 200
|
55
|
+
r.body # => "Qt5c1HWwCXDhKskMrBqMdQ"
|
56
|
+
|
57
|
+
# Handling errors
|
58
|
+
r = mock.post("http://api.example.com/users/authentify",
|
59
|
+
:Email => "jack@bauer.com", :Passwd => "bad")
|
60
|
+
r.status # => 403
|
61
|
+
r.body # => nil
|
62
|
+
|
10
63
|
|
11
64
|
== REQUIREMENTS
|
12
65
|
|
data/Rakefile
CHANGED
@@ -42,7 +42,16 @@ end
|
|
42
42
|
|
43
43
|
task :default => :test
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
if File.exist?('VERSION')
|
48
|
+
version = File.read('VERSION')
|
49
|
+
else
|
50
|
+
version = ""
|
51
|
+
end
|
52
|
+
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
54
|
+
rdoc.title = "FakeMechanize #{version}"
|
55
|
+
rdoc.rdoc_files.include('README*')
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
57
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fake_mechanize'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
# Small module to transform an url into its tiny form through TinyURL service.
|
6
|
+
module TinyUrl
|
7
|
+
TinyMatch = /http:\/\/tinyurl.com\/[a-z0-9]+/i
|
8
|
+
ApiAddress = "http://tinyurl.com/api-create.php"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def url_to_tiny(url)
|
12
|
+
return url if url.match(TinyMatch)
|
13
|
+
@cache ||= {}
|
14
|
+
@cache[url] ||= mechanize_agent.get(ApiAddress, :url => url).body
|
15
|
+
end
|
16
|
+
|
17
|
+
def mechanize_agent
|
18
|
+
@agent ||= WWW::Mechanize.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Test code part
|
24
|
+
# First, we have to define a FakeMechanize::Agent with some urls and their result
|
25
|
+
module TinyUrl
|
26
|
+
def self.mechanize_agent
|
27
|
+
if @http_agent.nil?
|
28
|
+
@http_agent = FakeMechanize::Agent.new do |mock|
|
29
|
+
mock.get :uri => ApiAddress,
|
30
|
+
:parameters => {:url => "http://www.google.com"},
|
31
|
+
:body => "http://tinyurl.com/dehdc"
|
32
|
+
mock.get :uri => ApiAddress,
|
33
|
+
:parameters => {:url => "https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2702-single-table-inherited-model-generator"},
|
34
|
+
:body => "http://tinyurl.com/pucvt5"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
@http_agent
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Now, we can write tests on this
|
42
|
+
class TinyUrlTest < Test::Unit::TestCase
|
43
|
+
def test_url_to_tiny_should_convert_url
|
44
|
+
assert_equal "http://tinyurl.com/dehdc", TinyUrl::url_to_tiny("http://www.google.com")
|
45
|
+
end
|
46
|
+
end
|
data/lib/fake_mechanize.rb
CHANGED
@@ -1,7 +1,61 @@
|
|
1
|
+
require 'rubygems'
|
1
2
|
require 'mechanize'
|
2
3
|
|
4
|
+
# = FakeMechanize module
|
5
|
+
# FakeMechanize provides methods and classes to write offline tests for applications which relies on Mechanize.
|
6
|
+
# == Examples
|
7
|
+
# # Initialize a fake agent
|
8
|
+
# @http_agent = FakeMechanize::Agent.new
|
9
|
+
#
|
10
|
+
# # Create answers and their params
|
11
|
+
# @http_agent.respond_to do |mock|
|
12
|
+
#
|
13
|
+
# # Answers to get queries to http://api.example.com/users/count?group=students
|
14
|
+
# # with the string "42"
|
15
|
+
# mock.get :uri => "http://api.example.com/users/count",
|
16
|
+
# :parameters => {:group => "students"},
|
17
|
+
# :body => "42"
|
18
|
+
#
|
19
|
+
# # Answers to post queries to http://api.example.com/users/3/activate
|
20
|
+
# # with the string "true"
|
21
|
+
# mock.post :uri => "http://api.example.com/users/3/activate",
|
22
|
+
# :body => "true"
|
23
|
+
#
|
24
|
+
# # Answers to post queries to http://api.example.com/users/authentify
|
25
|
+
# # with the string "Qt5c1HWwCXDhKskMrBqMdQ".
|
26
|
+
# # This example could be an authentication process
|
27
|
+
# mock.post :uri => "http://api.example.com/users/authentify",
|
28
|
+
# :parameters => {:Email => 'jack@bauer.com', :Passwd => 'secure'},
|
29
|
+
# :body => "Qt5c1HWwCXDhKskMrBqMdQ"
|
30
|
+
#
|
31
|
+
# # Will reply with an http error code of 403 with no body if the post query
|
32
|
+
# # to http://api.example.com/users/authentify does not have specified parameters.
|
33
|
+
# mock.error :uri => "http://api.example.com/users/authentify",
|
34
|
+
# :params_not_equal => {:Email => 'jack@bauer.com', :Passwd => 'secure'},
|
35
|
+
# :method => :post,
|
36
|
+
# :status => 403
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # Now you can use this agent like a real one
|
40
|
+
# r = mock.get("http://api.example.com/users/count", :group => "students")
|
41
|
+
# # => WWW::Mechanize::File
|
42
|
+
# r.body # => "42"
|
43
|
+
#
|
44
|
+
# # Posting
|
45
|
+
# r = mock.post("http://api.example.com/users/authentify",
|
46
|
+
# :Email => "jack@bauer.com", :Passwd => "secure")
|
47
|
+
# r.status # => 200
|
48
|
+
# r.body # => "Qt5c1HWwCXDhKskMrBqMdQ"
|
49
|
+
#
|
50
|
+
# # Handling errors
|
51
|
+
# r = mock.post("http://api.example.com/users/authentify",
|
52
|
+
# :Email => "jack@bauer.com", :Passwd => "bad")
|
53
|
+
# r.status # => 403
|
54
|
+
# r.body # => nil
|
55
|
+
#
|
3
56
|
module FakeMechanize
|
4
|
-
|
57
|
+
# Supported http verbs
|
58
|
+
HttpVerbs = [:get, :post]
|
5
59
|
end
|
6
60
|
|
7
61
|
require 'fake_mechanize/request'
|
data/lib/fake_mechanize/agent.rb
CHANGED
@@ -1,44 +1,70 @@
|
|
1
|
-
# = FakeMechanize module
|
2
|
-
# FakeMechanize provides methods and classes to write tests for applications which relies on Mechanize.
|
3
|
-
# == Examples
|
4
|
-
#
|
5
1
|
module FakeMechanize
|
6
2
|
# Agent acts like the original Mechanize::Agent but totally offline.
|
7
3
|
# It provides a respond_to method to predefine queries and their answers.
|
8
4
|
class Agent
|
5
|
+
# Represents a cookie jar built from WWW::Mechanize::CookieJar
|
9
6
|
attr_accessor :cookie_jar
|
10
7
|
|
11
|
-
|
8
|
+
# Create a new fake agent.
|
9
|
+
# Can be initialized with a block, see <tt>respond_to</tt> for more details.
|
10
|
+
def initialize(&block)
|
12
11
|
@cookie_jar = WWW::Mechanize::CookieJar.new
|
13
12
|
@responses = []
|
14
13
|
@errors = []
|
15
14
|
@history = []
|
15
|
+
|
16
|
+
respond_to(&block) if block_given?
|
16
17
|
end
|
17
18
|
|
18
19
|
def respond_to
|
19
20
|
reset_responses!
|
20
|
-
yield Responder.new(@responses, @errors)
|
21
|
+
yield Responder.new(@responses, @errors) if block_given?
|
21
22
|
@errors << ErrorRequest.new(:status => 404, :body => "not found")
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
-
|
25
|
+
# Returns true if query defined by <tt>method</tt>, <tt>uri</tt> and <tt>options</tt> was made.
|
26
|
+
# False otherwise.
|
27
|
+
# * <tt>method</tt> can be one of the following: :get, :post.
|
28
|
+
# * <tt>uri</tt> is a String that represents the called url.
|
29
|
+
# * <tt>options</tt> is an optional hash to specify parameters, headers ... Only :parameters options is actually supported.
|
30
|
+
def assert_queried(method, uri, options = {})
|
31
|
+
request = Request.new(:method => method, :uri => uri, :parameters => options[:parameters])
|
26
32
|
@history.any? {|history_query| history_query == request}
|
27
33
|
end
|
28
34
|
|
35
|
+
# Get method. Called like get method from the real Mechanize gem.
|
36
|
+
# Get can be achieved by two ways :
|
37
|
+
# * <tt>options</tt> is a String representing the url to call and <tt>parameters</tt> a hash for the parameters.
|
38
|
+
# * <tt>options</tt> is a Hash with <tt>:url</tt> the url and <tt>:params</tt> the parameters.
|
39
|
+
def get(options, parameters = nil)
|
40
|
+
if options.is_a? Hash
|
41
|
+
# TODO raise a Mechanize exception
|
42
|
+
raise "no url specified" unless url = options[:url]
|
43
|
+
parameters = options[:params]
|
44
|
+
else
|
45
|
+
url = options
|
46
|
+
end
|
47
|
+
return_mechanize_response Request.new(:method => :get, :uri => url, :parameters => parameters)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Post method. Called like post method from the real Mechanize gem.
|
51
|
+
# <tt>url</tt> is the url to post.
|
52
|
+
# <tt>query</tt> is a Hash of parameters.
|
53
|
+
def post(url, query = {})
|
54
|
+
return_mechanize_response Request.new(:method => :post, :uri => url, :parameters => query)
|
55
|
+
end
|
56
|
+
|
29
57
|
HttpVerbs.each do |method|
|
30
58
|
module_eval <<-EOE, __FILE__, __LINE__
|
31
|
-
def was_#{method}?(uri,
|
32
|
-
assert_queried(:#{method}, uri,
|
33
|
-
end
|
34
|
-
|
35
|
-
def #{method}(uri, args = {})
|
36
|
-
return_mechanize_response Request.new(:method => :#{method}, :uri => uri, :request_headers => args)
|
59
|
+
def was_#{method}?(uri, options = {})
|
60
|
+
assert_queried(:#{method}, uri, options)
|
37
61
|
end
|
38
62
|
EOE
|
39
63
|
end
|
40
64
|
|
41
65
|
protected
|
66
|
+
# Add <tt>given_request</tt> to history, search if for a matching query
|
67
|
+
# and returns a response or raise an error if http status is not 200.
|
42
68
|
def return_mechanize_response(given_request)
|
43
69
|
@history << given_request
|
44
70
|
request = search_for_request(given_request)
|
@@ -47,14 +73,18 @@ module FakeMechanize
|
|
47
73
|
page
|
48
74
|
end
|
49
75
|
|
76
|
+
# Search through available <tt>@responses</tt> if <tt>given_request</tt> matches one of the defined responses.
|
50
77
|
def search_for_request(given_request)
|
51
78
|
@responses.find {|request| request == given_request} || search_for_error_request(given_request)
|
52
79
|
end
|
53
80
|
|
81
|
+
# Search an error query in the error query list using match value for a request,
|
82
|
+
# the higher match will be the one returned (see ErrorRequest::match)
|
54
83
|
def search_for_error_request(given_request)
|
55
84
|
@errors.max_by {|request| request.match(given_request)}
|
56
85
|
end
|
57
86
|
|
87
|
+
# Delete all predefined responses
|
58
88
|
def reset_responses!
|
59
89
|
@responses.clear
|
60
90
|
end
|
@@ -1,12 +1,23 @@
|
|
1
1
|
module FakeMechanize
|
2
|
+
# ErrorRequest is like a traditionnal request, but implements features to match "error" cases :
|
3
|
+
# if you have an authentication process which auth user with only one login/password couple,
|
4
|
+
# you can define an ErrorRequest which will always match if parameters do not match your login/password.
|
5
|
+
# ErrorRequest also implements a <tt>match</tt> function which compute a matching value given another request.
|
2
6
|
class ErrorRequest < Request
|
7
|
+
# List of non matching parameters
|
3
8
|
attr_reader :params_not_equal
|
4
9
|
|
10
|
+
# Initialize an ErrorRequest.
|
11
|
+
# <tt>args</tt> takes all Request options and an additionnal <tt>:params_not_equal</tt> option
|
12
|
+
# to define a hash of parameters that should not match.
|
5
13
|
def initialize(args = {})
|
6
14
|
super
|
7
15
|
@params_not_equal = args[:params_not_equal]
|
8
16
|
end
|
9
17
|
|
18
|
+
# Compute a match between <tt>alt</tt> and current instance, returning an integer.
|
19
|
+
# Computation is based on http method, uri and request_headers.
|
20
|
+
# The idea behind this match rate is to find the best ErrorRequest matching a query.
|
10
21
|
def match(alt)
|
11
22
|
count = 0
|
12
23
|
|
@@ -15,9 +26,10 @@ module FakeMechanize
|
|
15
26
|
count += 1 if uri == alt.uri
|
16
27
|
|
17
28
|
# More complicated: evaluates if params are equals or if they are different on purpose
|
18
|
-
|
29
|
+
# TODO : handle headers
|
30
|
+
if !parameters.empty? and parameters == alt.parameters
|
19
31
|
count += 1
|
20
|
-
elsif method == alt.method and uri == alt.uri and
|
32
|
+
elsif method == alt.method and uri == alt.uri and parameters != params_not_equal
|
21
33
|
count += 1
|
22
34
|
end
|
23
35
|
|
@@ -2,13 +2,35 @@ module FakeMechanize
|
|
2
2
|
# Request represents a request made to the server with its specific headers and its answer body, headers
|
3
3
|
# and status (http code)
|
4
4
|
class Request
|
5
|
-
|
5
|
+
# HTTP Method (get, post, ...)
|
6
|
+
attr_reader :method
|
7
|
+
# URI in its full form
|
8
|
+
attr_reader :uri
|
9
|
+
# Headers passed along with the request
|
10
|
+
attr_reader :request_headers
|
11
|
+
# Parameters passed with query (post or get)
|
12
|
+
attr_reader :parameters
|
13
|
+
# Body passed on answer
|
14
|
+
attr_reader :body
|
15
|
+
# HTTP Status code (200, 404, ...)
|
16
|
+
attr_reader :status
|
17
|
+
# Responses headers passed with status and body
|
18
|
+
attr_reader :response_headers
|
6
19
|
|
20
|
+
# Create a new Request with the following options :
|
21
|
+
# * <tt>:method</tt>: http method (verb) to respond to (:get, :post, ...).
|
22
|
+
# * <tt>:uri</tt> or <tt>:url</tt>: string which represents the queried url.
|
23
|
+
# * <tt>:request_headers</tt>: optionnals headers passed while querying.
|
24
|
+
# * <tt>:parameters</tt>: an optionnals hash of parameters, like the one passed in an html form or inlined in a get query.
|
25
|
+
# * <tt>:body</tt>: body that should be returned if query match. Defaut is nil.
|
26
|
+
# * <tt>:status</tt>: http status response code (200, 404, ...). Default is 200.
|
27
|
+
# * <tt>:response_headers</tt>: an optionnal hash for response headers.
|
7
28
|
def initialize(args = {})
|
8
29
|
# Query
|
9
30
|
@method = args[:method] || :get
|
10
|
-
@uri = args[:uri]
|
31
|
+
@uri = args[:url] || args[:uri]
|
11
32
|
@request_headers = args[:request_headers] || {}
|
33
|
+
@parameters = args[:parameters] || {}
|
12
34
|
|
13
35
|
# Answer
|
14
36
|
@body = args[:body]
|
@@ -20,7 +42,10 @@ module FakeMechanize
|
|
20
42
|
# Returns true if equal, false otherwise.
|
21
43
|
# Evaluation is based on method, uri and request_headers.
|
22
44
|
def ==(alt)
|
23
|
-
method == alt.method and
|
45
|
+
method == alt.method and
|
46
|
+
uri == alt.uri and
|
47
|
+
request_headers == alt.request_headers and
|
48
|
+
parameters == alt.parameters
|
24
49
|
end
|
25
50
|
end # Request
|
26
51
|
end # FakeMechanize
|
@@ -1,9 +1,12 @@
|
|
1
1
|
module FakeMechanize
|
2
|
+
# Responder is a class responsible for creation of responses and errors requests.
|
2
3
|
class Responder
|
3
4
|
def initialize(responses, errors)
|
4
5
|
@responses, @errors = responses, errors
|
5
6
|
end
|
6
7
|
|
8
|
+
# Create a new error request. See ErrorRequest for options.
|
9
|
+
# If <tt>:method</tt> is omited, all http verbs can answer.
|
7
10
|
def error(args)
|
8
11
|
if args[:method]
|
9
12
|
@errors << ErrorRequest.new(args)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fake_mechanize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fabien Jakimowicz
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-10-30 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -38,6 +38,7 @@ files:
|
|
38
38
|
- README.rdoc
|
39
39
|
- Rakefile
|
40
40
|
- VERSION
|
41
|
+
- examples/tiny_url.rb
|
41
42
|
- lib/fake_mechanize.rb
|
42
43
|
- lib/fake_mechanize/agent.rb
|
43
44
|
- lib/fake_mechanize/error_request.rb
|
@@ -47,6 +48,8 @@ files:
|
|
47
48
|
- test/test_helper.rb
|
48
49
|
has_rdoc: true
|
49
50
|
homepage: http://github.com/jakimowicz/fake_mechanize
|
51
|
+
licenses: []
|
52
|
+
|
50
53
|
post_install_message:
|
51
54
|
rdoc_options:
|
52
55
|
- --charset=UTF-8
|
@@ -67,10 +70,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
70
|
requirements: []
|
68
71
|
|
69
72
|
rubyforge_project: fake-mechanize
|
70
|
-
rubygems_version: 1.3.
|
73
|
+
rubygems_version: 1.3.5
|
71
74
|
signing_key:
|
72
|
-
specification_version:
|
75
|
+
specification_version: 3
|
73
76
|
summary: toolset for offline unit tests on mechanize, like httpmock
|
74
77
|
test_files:
|
75
78
|
- test/fake_mechanize_test.rb
|
76
79
|
- test/test_helper.rb
|
80
|
+
- examples/tiny_url.rb
|