How to display the input of those expectations which were wrong? - ruby

I am testing a static class method, passing many different inputs into it. Since each input is quite big, I saved the list somewhere and pass each to the method in a loop.
However I realize that the errors does not display the input to these methods, making it difficult to debug. Is there a way to display this instead?

Perhaps you could label the inputs (e.g. in an hash) and use the labels to create the example titles, so that you know which input produced the unexpected results?
E.g.
INPUTS = {
"returns an error when input is too big" => { :input => ..., :output => ... },
"returns an error when input too small" => { :input => ..., :output => ... },
"returns a pony when input is just right" => { :input => ..., :output => ... },
}
INPUTS.each do |title, bundle|
it title do
StaticClass.method(bundle[:input]).should == bundle[:output]
end
end
This example is silly; obviously, you'd want to load your data out of yaml files or whatever, but I was too lazy to pop demo code for that. Dir.glob.somethingorother. :-)
Also, note that the problem you're trying to solve is an inherent problem in fixture-driven tests; you have to look somewhere outside the example code to see what the example code was doing. If you can avoid fixture-driven tests, I recommend that you do so.

Related

selecting elements using variables in ruby /watir

The real issue I am encountering is the delay on population of drop down lists in a web page.
The call i am using in the script is :-
clickOndropDown(":id","dropDownAutocomplete","ABC",#b)
where
1. clickOndropDown is the method invoked
2. id is the element selector (which can be :id,xpath, or :css [which are different selectors in my html code for different dropdown boxes] to handle all cases within the code)
3. ABC is the element to be selected from the drop down list
4. #b is the browser object
the function definition is as :
def clickOndropDown(identifier,selector,targetVal,br)
begin
puts "starting off" # gets printed
br.element("#{identifier}" => "#{selector}").fire_event :click #--- does not work---
# br.element(:id => "#{selector}").fire_event :click #--- works
puts "inside selector pass 1"
br.element(:link, targetVal).fire_event :click
...
...
# rest of the code
It does not throw any exception..just does the push statement before the selection statement.
is there any wild card handler for # (--"#{identifier}" ) so that I can write a single code for handling id,xpath,or css
I am surprised that there is no exception. I would expect a MissingWayOfFindingObjectException.
The problem is that the identifier is a String instead of a Symbol. The line that is not working is equivalent to:
br.element(":id" => "dropDownAutocomplete")
Which is not the same as:
br.element(:id => "dropDownAutocomplete")
Notice the difference between the String, ":id", and the Symbol, :id.
You should change the method call to send a Symbol and change the method to no longer change it to a String:
def clickOndropDown(identifier,selector,targetVal,br)
br.element(identifier => selector).fire_event :click
end
clickOndropDown(:id,"dropDownAutocomplete","ABC",#b)
If you want to have a more versatile method, you would be better off to have the clickOndropDown accept a Hash for the locator. This would allow you to accept multiple locator criteria.
def click_on_dropdown(br, target_val, locator)
br.element(locator).fire_event :click
end
# Call for the original example
click_on_dropdown(#b, "ABC", id: "dropDownAutocomplete")
# Call with multiple selectors
click_on_dropdown(#b, "ABC", id: "dropDownAutocomplete", name: "name_value")

Not able to call instance_double twice

I'm writing a test fot rspec to check that items are added into a class that I use like an array
describe '#collection' do
let(:process) {
instance_double("WebServerProcess", :cpu => 33, :mem => 22, :pid => 1, :port => 8000)
}
it 'return the collection' do
WebServersCollection.add process
expect(subject.collection).to eq([process])
end
it 'should add with <<' do
WebServersCollection << process
expect(subject.collection).to eq([process])
end
end
Show me this error
Failure/Error: expect(subject.collection).to eq([process])
# was originally created in one example but has leaked into another example and can no
longer be used. rspec-mocks' doubles are designed to only last for one
example, and you need to create a new one in each example you wish to
use it for.
I think the error tells you everything you need to know.
You can't do that and
you need to create a new one in each example you wish to use it for

Render Inversion template from hash

Is it possible to render an Inversion template from a hash? And if not, how does one construct a complex template corresponding to a hash such as:
{ :a => [ { :b => 'foo', :c => 'bar' }, { :d => 'blah', :e => 'blubb'} ] }
Unfortunately the user guide doesn't show such examples.
It depends on how you want to render the hash. Assuming the code:
require 'inversion'
the_hash = { :a => [
{ :b => 'foo', :c => 'bar' },
{ :d => 'blah', :e => 'blubb'}
] }
You can render it as-is, of course:
<!-- prettyprint.tmpl -->
<code><?pp the_hash ?></code>
and then:
tmpl = Inversion::Template.load( 'prettyprint.tmpl' )
tmpl.the_hash = the_hash
puts tmpl.render
which will render as:
<!-- prettyprint.tmpl -->
<code>{:a=>[{:b=>"foo", :c=>"bar"}, {:d=>"blah", :e=>"blubb"}]}</code>
Assuming you want to do something more complex with the hash, like render some of its members:
<!-- members.tmpl -->
A's first B is: <?call the_hash[:a].first[:b] ?>
A's first C is: <?call the_hash[:a].first[:c] ?>
A's second D is: <?call the_hash[:a][1][:d] ?>
A's second E is: <?call the_hash[:a][1][:e] ?>
which (with the same code as the previous example except loading 'members.tmpl' instead) will render like so:
<!-- members.tmpl -->
A's first B is: foo
A's first C is: bar
A's second D is: blah
A's second E is: blubb
But building a big complex data structure like your hash, and then later merging it with a template is not really how Inversion is intended to be used. The idea is really that loading the template gives you a Ruby object with an API, suitable for passing around and incrementally adding stuff to before rendering it. Instead of building a hash, just pass the template object itself around and call accessors on it, then let it pull out what it needs to build the view:
tmpl.users = User.all
tmpl.company = "ACME Widgets, Pty"
tmpl.render
This also has the advantage of being more amenable to mocking:
# (rspec)
tmpl = mock( "members template" )
tmpl.should_receive( :users ).with( User.all )
tmpl.should_receive( :company ).with( company_name )
tmpl.should_receive( :render ).and_return( "the rendered stuff" )
This removes the template contents from the test entirely, and just focuses on what messages the controller should be sending to the view.
There's a fairly full-featured example in the manual, along with the code that renders it.
The library (and its documentation) are fairly new, so thanks for bringing this up. I have a pending patch to merge the manual with the API docs, which should help, but in the meantime it's probably the best place to find examples.
Hope this helps. I'm happy to answer more in-depth questions personally (ged at FaerieMUD.org), or accept patches via pull request on Github or Bitbucket.

How to share data between implementation and description of a spec?

I wonder if there's any good way to reuse data between implementation and description of a spec... More particularly, I'd like to be able do something like the following:
describe "#some_method" do
let(:arg1) { "Sample String 1" }
let(:arg2) { "Sample String 2" }
context "with '#{arg1}', its result" do
specify { some_method(arg1).should == 1 }
end
context "with '#{arg2}', its result" do
specify { some_method(arg2).should == 2 }
end
end
Of course, this code won't work - arg1 and arg2 are not accessible outside of spec bodies.
Is it possible to achieve the similar result without using global variables or external classes?
Update:
I'm interested in the output of the spec. Something like this:
#some_method
with 'Sample String 1' its result
should == 1
with 'Sample String 2' its result
should == 2
The answer is that you don't use dynamic descriptions. The RSpec way to do this would be
describe "#some_method" do
it "extracts the number correctly" do
some_method("Sample String 1").should == 1
some_method("Sample String 2").should == 2
end
end
It is no problem to hard-code test data in your specs. If you want more complete output, you can use a custom matcher
require 'rspec'
class Test
def some_method(str)
str[/[0-9]+/].to_i
end
end
RSpec::Matchers.define :return_value_for_argument do |result, arg|
match do |actual|
actual.call(arg) == result
end
description do
"return #{result.inspect} for argument #{arg.inspect}"
end
end
describe Test do
let(:test) { Test.new }
describe "#some_method" do
subject { test.method(:some_method) }
it { should return_value_for_argument 1, "str 1" }
end
end
When doing API testing, I find it incredibly useful to be able to see the path, params, and response of each test. I have used the very useful tips given by Jeff Nyman to store things in the example.metatadata[:thing_i_want_to_store_like_url] of each test and with a custom formatter, print it out.
So my tests output look something like this:
that jonathan does not know it exists
:path : /user/20
:params: {}
=> response: {"error"=>{"message"=>"error", "code"=>404}}
that jonathan cannot edit
:path : /user/20/update
:params: {:name=>"evil_name"}
=> response: {"error"=>{"message"=>"error", "code"=>404}}
It's not appropriate to cite specific arguments in your descriptions. Your descriptions should provide a human-readable description of the desired behavior, without reference to specific arguments in most cases.

How do I get an array of check boxes in haml?

I have an array of strings, called #theModels, in a routine implemented as part of a Sinatra server. These models are options for the user to select, and are obtained by the back end (the idea being, as new models are added, then the front end code should not change).
I'm using haml to render html.
How can I enumerate each element in the list of #theModels such that each element is a checkbox? And how can I obtain which checkboxes the user has selected?
I see that just putting
= #theModels
will give me the list of strings contained in #theModels, but without spacing or the like, and certainly not in checkboxes. I've found this question that appears to be similar, but my haml-fu isn't good enough to convert that into what I need.
UPDATE:
These are options associated with a file upload, such that now the code looks like:
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
- #theModelHash.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%input{:type=>"file",:name=>"file"}
%input{:type=>"submit",:value=>"Upload"}
Problem is, that puts a file upload button on each option, instead of at the end. I only want one submit button in the end; should I have two forms that both report their results when the 'Upload' button is pressed?
UPDATE2:
After a moment's thought, the above can be modified to:
Thanks!
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
- #theModelHash.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%form{:action=>"/Upload",:method=>"post",:enctype=>"multipart/form-data"}
%input{:type=>"file",:name=>"file"}
%input{:type=>"submit",:value=>"Upload"}
And that appears to do what I want.
I think you should send the content as an hash instead.
This will give you the opportunity to set initial values in the form.
The hash #params will give you the result.
E.g. {"oranges"=>"1"}
#app.haml
%form{:method => 'post', :action => "/"}
- #models.each do |key,value|
%br
%input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
=key
%input{:type => :submit, :value => "Save"}
#app.rb
require 'sinatra'
require 'haml'
get '/' do
#models = {"oranges" => true, "bananas" => false}
haml :app
end
post '/' do
#params.inspect
end
The link you provided linked to a rails solution where you have a function returning the proper html.
You can define this function yourself:
Input: key, value
Output: %input{:type=>"checkbox", :name=>"#{key}", :value=>1, :checked=>value}
def check_box(key, value)
...
end
and call it in haml with
=check_box(key,value)

Resources