lib/umlaut/test_help.rb
require 'vcr'
module Umlaut
# Some methods helpful in writing automated tests against Umlaut. Used in
# Umlaut, can also be used in your local app or Umlaut plugin.
#
# Add to your test_helper.rb:
#
# require 'umlaut/test_help'
# include Umlaut::TestHelp
module TestHelp
# Methods you can use to make a mocked up Rails Request and corersponding Umlaut Request
# Pass in a URL, absolute or partial, eg "/resolve?isbn=X"
def fake_rails_request(umlaut_url)
# hard to figure out how to mock a request, this seems to work
ActionController::TestRequest.new(Rack::MockRequest.env_for(umlaut_url))
end
def fake_umlaut_request(umlaut_url)
rails_request = fake_rails_request(umlaut_url)
Request.find_or_create(rails_request.params, {}, rails_request)
end
# The list of configured services is global state. Sometimes
# we want to test with a specific configuration list. An experimental
# hacky way to let you do that. Yes, this is a smell of a bad design,
# but we do what we can.
#
# This is in progress and still needs more api, this is still too hard.
def with_service_config(hash)
original = ServiceStore.config
ServiceStore.config = hash
yield
ensure
ServiceStore.config = original
end
# Assert that, for a given request, a service with a given id registered
# a DispatchedService with status DispatchedService::Succesful
# assert_dispatched(umalut_request, "service_id")
#
# Assert that a service with a given id registered a DispatchedService
# with another status.
# assert_dispatched(umlaut_request, "service_id", DispatchedService::FailedTemporary)
def assert_dispatched(request, service_id, status = DispatchedService::Successful)
dispatched = request.dispatched_services.to_a.find {|ds| ds.service_id == service_id}
assert dispatched.present?, "No DispatchedService record for service_id `#{service_id}`"
if status
assert_equal status, dispatched.status
end
end
# Assert that for a given umlaut request, a service with a given ID
# recorded at least one ServiceResponse of any type:
# assert_service_responses(umlaut_service, "service_id")
#
# Assert that it recorded exactly `number` of ServiceResponses
# assert_service_responses(umlaut_service, 'service_id', :number => 5)
#
# Assert that it recorded some ServiceResponses, and _at least one_ of those
# ServiceResponses was of each of the kind(s) specified. With or without
# :number.
# assert_service_resposnes(umlaut_service, 'service_id', :includes_type => :fulltext)
# assert_service_resposnes(umlaut_service, 'service_id', :number => 5, :includes_type => :fulltext)
# assert_service_resposnes(umlaut_service, 'service_id', :number => 5, :includes_type => [:fulltext, :highlighted_link])
#
# On assertion success, the method will return the array of ServiceResponse
# objects found, OR if :number => 1, the single ServiceResponse not in an array
# for convenience.
def assert_service_responses(request, service_id, options = {})
number = options[:number]
type_names = Array(options[:includes_type])
responses = request.service_responses.to_a.find_all {|r| r.service_id == service_id}
if number
assert_equal number, responses.length, "Found #{responses.length} ServiceResponses from service id `#{service_id}`, expected #{number}"
else
assert responses.length > 0, "No ServiceResponse found for service id `#{service_id}"
end
type_names.each do |kind|
assert responses.find {|sr| sr.service_type_value_name == kind.to_s}, "The generated ServiceResponses for service id `#{service_id}` must include type #{kind}" if number.to_i > 0
end
if number == 1
return responses.first
else
return responses
end
end
# Keep it in a seperate module so people can include just that if they want
# Umlaut::TestHelp::TestWithCassette. If you've already included Umlaut::TestHelp
# into your
module TestWithCassette
# Helper to create a Test::Unit style test that is wrapped in
# VCR.use_cassette for testing. If you supply a 'group' option,
# then the cassettes will be placed on the file system in a directory
# based on that group, and the VCR cassettes will also be tagged
# with that group name.
#
# Extract this whole thing to a gem for sharing?
#
# An alternative to this method is using rspec (but not in Umlaut,
# we don't use rspec) OR using minitest-rails or minitest-spec-rails
# with minitest/spec style and the minitest-vcr gem. I've had mixed
# success with minitest/spec in rails.
#
# extend TestWithCassette
# test_with_cassette("do something", :group) do
# assert_...
# end
def test_with_cassette(name, group = nil, vcr_options ={}, &block)
# cribbed from Rails and modified for VCR
# https://github.com/rails/rails/blob/b451de0d6de4df6bc66b274cec73b919f823d5ae/activesupport/lib/active_support/testing/declarative.rb#L25
test_name_safe = name.gsub(/\s+/,'_')
test_method_name = "test_#{test_name_safe}".to_sym
raise "#{test_method_name} is already defined in #{self}" if methods.include?(test_method_name)
cassette_name = vcr_options.delete(:cassette)
unless cassette_name
# calculate default cassette name from test name
cassette_name = test_name_safe
# put in group subdir if group
cassette_name = "#{group}/#{cassette_name}" if group
end
# default tag with groupname, can be over-ridden.
vcr_options = {:tag => group}.merge(vcr_options) if group
if block_given?
define_method(test_method_name) do
VCR.use_cassette(cassette_name , vcr_options) do
instance_eval &block
end
end
else
define_method(test_method_name) do
flunk "No implementation provided for #{name}"
end
end
end
end
end
end