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.
@@ -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