fake_mechanize 0.0.1 → 0.0.2
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/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
|