In selenium ruby tests can I combine the setup and teardown methods into one location for all my tests? - ruby

In my ruby Selenium Tests there is a lot of the same code in every test. How can I best share code between tests? For example my setup and teardown methods are the same in every file, how can I remove them from every file into one shared file or is that even possible?
def setup
#verification_errors = []
#selenium = Selenium::Client::Driver.new \
:host => "#$sell_server",
:port => 4444,
:browser => "#$browser",
:url => "http://#$network.#$host:2086/",
:timeout_in_second => 60
#selenium.start_new_browser_session
end
def teardown
#selenium.close_current_browser_session
assert_equal [], #verification_errors
end
I've tried putting setup in a shared module and a required file but both present different problems with inheritance of the other methods that need access to the #selenium object that is started. What would be a good design if there is one for sharing the code?

I'm not really sure what test framework you're using, but in rspec you could place it into your spec_helper file and just do a before(:each) / after(:each). I'd check the callback documentation for your framework of choice.

For test unit framework - it seems to work to create a SharedTest class to inherit from Test::Unit::Testcase with setup and teadown methods. Then just subclass the test files SharedTest. The only negative consequence I've found is I had to add a test_default method that does nothing in SharedTest to get it to work. If I name my test method test_default that overides it and seems ok, but not very descriptive...
sharedtest.rb
class SharedTest < Test::Unit::Testcase
def setup
#verification_errors = []
#selenium = Selenium::Client::Driver.new \
:host => "#$sell_server",
:port => 4444,
:browser => "#$browser",
:url => "http://#$network.#$host:2086/",
:timeout_in_second => 60
#selenium.start_new_browser_session
end
def teardown
#selenium.close_current_browser_session
assert_equal [], #verification_errors
end
def test_default
#puts self
end
end
T01_testcasename.rb
class Test_01_whatever < SharedTest
def test_default
#test code
end
I'm still open to better solutions but this seems to be working for me.

Related

EM::Synchrony.defer with fiber aware database call causes FiberError exception

I'm trying to use EM-Synchrony for concurrency in an application and have come across an issue with my use of deferred code and Fibers.
Any calls to the database within either EM.defer or EM::Synchrony.defer results in the application crashing with the error can't yield from root fiber
Below is a very trimmed down runnable example of what I'm trying to accomplish. The first print works and displays [:first, 1] but the second is where I crash with the error mentioned above.
require 'mysql2'
require 'em-synchrony/activerecord'
ActiveRecord::Base.establish_connection(
:adapter => 'em_mysql2',
:username => 'user',
:password => 'pass',
:host => 'localhost',
:database => 'app_dev',
:pool => 60
)
class User < ActiveRecord::Base; end
EM.synchrony do
p [:first, User.all.count]
EM::Synchrony.defer do
p [:second, User.all.count]
end
end
My first thought was perhaps the Fiber.current and Fiber.yield within EM::Synchrony.defer meant I could fix the problem with an extra Fiber.new call
EM::Synchrony.defer do
Fiber.new do
p [:second, User.all.count]
end.resume
end
This fails to run as well but this time I get the error fiber called across threads.

Ruby structure for extendable handler/plugin architechture

I'm writing something that is a bit like Facebook's shared link preview.
I would like to make it easily extendable for new sites by just dropping in a new file for each new site I want to write a custom parser for. I have the basic idea of the design pattern figured out but don't have enough experience with modules to nail the details. I'm sure there are plenty of examples of something like this in other projects.
The result should be something like this:
> require 'link'
=> true
> Link.new('http://youtube.com/foo').preview
=> {:title => 'Xxx', :description => 'Yyy', :embed => '<zzz/>' }
> Link.new('http://stackoverflow.com/bar').preview
=> {:title => 'Xyz', :description => 'Zyx' }
And the code would be something like this:
#parsers/youtube.rb
module YoutubeParser
url_match /(youtube\.com)|(youtu.be)\//
def preview
get_stuff_using youtube_api
end
end
#parsers/stackoverflow.rb
module SOFParser
url_match /stachoverflow.com\//
def preview
get_stuff
end
end
#link.rb
class Link
def initialize(url)
extend self with the module that has matching regexp
end
end
# url_processor.rb
class UrlProcessor
# registers url handler for given pattern
def self.register_url pattern, &block
#patterns ||= {}
#patterns[pattern] = block
end
def self.process_url url
_, handler = #patterns.find{|p, _| url =~ p}
if handler
handler.call(url)
else
{}
end
end
end
# plugins/so_plugin.rb
class SOPlugin
UrlProcessor.register_url /stackoverflow\.com/ do |url|
{:title => 'foo', :description => 'bar'}
end
end
# plugins/youtube_plugin.rb
class YoutubePlugin
UrlProcessor.register_url /youtube\.com/ do |url|
{:title => 'baz', :description => 'boo'}
end
end
p UrlProcessor.process_url 'http://www.stackoverflow.com/1234'
#=>{:title=>"foo", :description=>"bar"}
p UrlProcessor.process_url 'http://www.youtube.com/1234'
#=>{:title=>"baz", :description=>"boo"}
p UrlProcessor.process_url 'http://www.foobar.com/1234'
#=>{}
You just need to require every .rb from plugins directory.
If you're willing to take this approach you should probably scan the filed for the mathing string and then include the right one.
In the same situation I attempted a different approach. I'm extending the module with new methods, ##registering them so that I won't register two identically named methods. So far it works good, though the project I started is nowhere near leaving the specific domain of one tangled mess of a particular web-site.
This is the main file.
module Onigiri
extend self
##registry ||= {}
class OnigiriHandlerTaken < StandardError
def description
"There was an attempt to override registered handler. This usually indicates a bug in Onigiri."
end
end
def clean(data, *params)
dupe = Onigiri::Document.parse data
params.flatten.each do |method|
dupe = dupe.send(method) if ##registry[method]
end
dupe.to_html
end
class Document < Nokogiri::HTML::DocumentFragment
end
private
def register_handler(name)
unless ##registry[name]
##registry[name] = true
else
raise OnigiriHandlerTaken
end
end
end
And here's the extending file.
# encoding: utf-8
module Onigiri
register_handler :fix_backslash
class Document
def fix_backslash
dupe = dup
attrset = ['src', 'longdesc', 'href', 'action']
dupe.css("[#{attrset.join('], [')}]").each do |target|
attrset.each do |attr|
target[attr] = target[attr].gsub("\\", "/") if target[attr]
end
end
dupe
end
end
end
Another way I see is to use a set of different (but behaviorally indistinguishable) classes with a simple decision making mechanism to call a right one. A simple hash that holds class names and corresponding url_matcher would probably suffice.
Hope this helps.

How do I inherit default data from a module or class

I am working on an application to automate testing for SQL injection vulnerability. It is currently named Deft and is for a University project.
I want to be able to run tests from a command line, or an interactive console. I am coding several classes. (Deft::Cli, Deft::Console etc.)
Here's what I think I'd like to do.
module Deft
module App
attr_accessor :origin
#origin = { "host" => "localhost", "port" => "80" }
end
end
module Deft
class Console
include App
def initialize
puts origin
end
end
end
The example has been simplified, but the point is that the default values (and structure) get defined in the Deft::App module.
The problem as I can tell is that although methods.grep(/origin/) from inside a console instance does indeed give me ["origin=", "origin"] calling origin returns nil. Instead of the values I define in Deft::App. It makes sense that it doesn't work, but I don't know how to make it work.
Perhaps I'm taking the simplified example too literally, but one way to fix it is to get rid of the attr_accessor class method invocation and just make origin be the constant Origin or ORIGIN.
What about this?
module Deft
class DefaultConsole
attr_accessor :origin
def initialize
#origin = {'host' => 'localhost', 'port' => 80}
end
end
class Console < DefaultConsole
def initialize
super
puts origin
end
end
end
Deft::Console.new
# => {'host' => 'localhost', 'port' => 80}
Try like this:
module Deft
module App
attr_accessor :origin
def init
#origin = { "host" => "localhost", "port" => "80" }
end
end
end
module Deft
class Console
include App
def initialize
init
puts origin
end
end
end
Deft::Console.new
Thanks to everyone that added their input. I'm going to go ahead and answer my own question, this works as I had hoped.
module Deft
module App
##origin = { "host" => "localhost", "port" => "80" }
def origin ; ##origin ; end
def origin=(args) ; ##origin=(args) ; end
end
end
If anyone wants to copy and clean this up using attr_accesor then I'd be happy to edit this back into my question and accept their answer.

Why am I getting "Test is not a class" in this Ruby script?

I've got a problem with this class
require "test/unit"
require "selenium/client"
class Test < Test::Unit::TestCase
def setup
#verification_errors = []
#selenium = Selenium::Client::Driver.new \
:host => "localhost",
:port => 4444,
:browser => "*chrome",
:url => "http://change-this-to-the-site-you-are-testing/",
:timeout_in_second => 60
#selenium.start_new_browser_session
end
def teardown
#selenium.close_current_browser_session
assert_equal [], #verification_errors
end
def test_test
#selenium.open "/apj/gestionnaire/flux.ex"
#selenium.wait_for_pop_up "_self", "30000"
end
end
it says to me that it's not a class :
/test.rb:4: Test is not a class (TypeError)
from C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
from C:/Ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from C:/Documents and Settings/Micro/My Documents/Aptana RadRails Workspace/.metadata/.plugins/org.rubypeople.rdt.testunit/ruby/RemoteTestRunner.rb:301
anyone have any idea ?
Regards
Bussiere
Using Test as your class name is a bad idea. It's an existing constant (referring to a module) as soon you require test/unit
require "test/unit"
Test.class # => Module
Use a different name for your test case.
Using Test as your class name is a bad idea.
Wrong ! Today a new version of the rspec-rails gem has been released fixing this issue in some cases.
You can take a look at the the changelog file:
Fix "Test is not a class (TypeError)" error when using a custom Test class in Rails 4.1 and 4.2. (Aaron Kromer, #1295)

Selenium Ruby Reporting

I'm trying to set the environment for testing using Selenium and selenium-client gem.
I prefer unit test style over RSpec style of tests.
Do I have to build my own system for reporting then?
How can I add exception handling without having begin-rescue-end in each test? Is there any way to do that using mixins?
I'm not sure I understand what your question means in terms of reporting but the selenium-client gem handles both BDD and UnitTesting.
Below is code copied from the rubyforge page:
require "test/unit"
require "rubygems"
gem "selenium-client", ">=1.2.16"
require "selenium/client"
class ExampleTest < Test::Unit::TestCase
attr_reader :browser
def setup
#browser = Selenium::Client::Driver.new \
:host => "localhost",
:port => 4444,
:browser => "*firefox",
:url => "http://www.google.com",
:timeout_in_second => 60
browser.start_new_browser_session
end
def teardown
browser.close_current_browser_session
end
def test_page_search
browser.open "/"
assert_equal "Google", browser.title
browser.type "q", "Selenium seleniumhq"
browser.click "btnG", :wait_for => :page
assert_equal "Selenium seleniumhq - Google Search", browser.title
assert_equal "Selenium seleniumhq", browser.field("q")
assert browser.text?("seleniumhq.org")
assert browser.element?("link=Cached")
end
end
As for exception handling, UnitTesting handles the exceptions with an Error message.
That being said, I may have misunderstood your question.
Initial build of Extent is available for Ruby. You can view the sample here. Latest source is available at github.
Sample code:
# main extent instance
extent = RelevantCodes::ExtentReports.new('extent_ruby.html')
# extent-test
extent_test = extent.start_test('First', 'description string')
# logs
extent_test.log(:pass, 'step', 'details')
extent.end_test(extent_test)
# flush to write everything to html file
extent.flush

Resources