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.
@@ -1,12 +1,65 @@
1
1
  = fake-mechanize
2
2
 
3
3
  == DESCRIPTION
4
- Description goes here.
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
- desc "build rdoc using hanna theme"
46
- task :rdoc do
47
- `rm -rf rdoc && rdoc --op=rdoc --title=FakeMechanize --inline-source --format=darkfish LICENSE README* lib/**/*.rb`
48
- end
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
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
@@ -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
- HttpVerbs = [:head, :get, :post, :put, :delete]
57
+ # Supported http verbs
58
+ HttpVerbs = [:get, :post]
5
59
  end
6
60
 
7
61
  require 'fake_mechanize/request'
@@ -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
- def initialize
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
- def assert_queried(method, uri, params = {})
25
- request = Request.new(:method => method, :uri => uri, :request_headers => params)
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, params = {})
32
- assert_queried(:#{method}, uri, params)
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
- if !request_headers.empty? and request_headers == alt.request_headers
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 request_headers != params_not_equal
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
- attr_reader :method, :uri, :request_headers, :body, :status, :response_headers
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 uri == alt.uri and request_headers == alt.request_headers
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.1
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-07-23 00:00:00 +02:00
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.1
73
+ rubygems_version: 1.3.5
71
74
  signing_key:
72
- specification_version: 2
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