Disable a group of tests in rspec? - ruby

I have a test spec which describes a class and within that has various contexts each with various it blocks.
Is there a way I can disable a context temporarily?
I tried adding a pending "temporarily disabled" call at the very top within a context I want to disable, and I did see something about pending when I ran the spec but then it just continued to run the rest of the tests.
This is what I kind of had:
describe Something
context "some tests" do
it "should blah" do
true
end
end
context "some other tests" do
pending "temporarily disabled"
it "should do something destructive" do
blah
end
end
end
but like I said it just went on to run the tests underneath the pending call.
Searching led me to this mailing list thread in which the the creator (?) of rspec says it's possible in rspec 2, which I'm running. I guess it did work but it didn't have the desired effect of disabling all of the following tests, which is what I think of when I see a pending call.
Is there an alternative or am I doing it wrong?

To disable a tree of specs using RSpec 3 you can:
before { skip }
# or
xdescribe
# or
xcontext
You can add a message with skip that will show up in the output:
before { skip("Awaiting a fix in the gem") }
with RSpec 2:
before { pending }

Use exclusion filters.
From that page:
In your spec_helper.rb (or rails_helper.rb)
RSpec.configure do |c|
c.filter_run_excluding :broken => true
end
In your test:
describe "group 1", :broken => true do
it "group 1 example 1" do
end
it "group 1 example 2" do
end
end
describe "group 2" do
it "group 2 example 1" do
end
end
When I run "rspec ./spec/sample_spec.rb --format doc"
Then the output should contain "group 2 example 1"
And the output should not contain "group 1 example 1"
And the output should not contain "group 1 example 2"

See what you think of this:
describe "something sweet", pending: "Refactor the wazjub for easier frobbing" do
it "does something well"
it "rejects invalid input"
end
I like to see reasons with my pending items when I'm disabling something for "a while". They serve as little comments/TODOs that are presented regularly rather than buried in a comment or an excluded example/file.
Changing it to pending or xit is quick and easy, but I prefer the hash construction. It gives you every-run documentation, is a drop-in (doesn't change describe/context/it so I have to decide what to use again later), and is just as easily removed if the decision is made or blocker is removed.
This works the same for groups and individual examples.

another one. https://gist.github.com/1300152
use xdescribe, xcontext, xit to disable it.
Update:
Since rspec 2.11, it includes xit by default. so the new code will be
# put into spec_helper.rb
module RSpec
module Core
module DSL
def xdescribe(*args, &blk)
describe *args do
pending
end
end
alias xcontext xdescribe
end
end
end
Usage
# a_spec.rb
xdescribe "padding" do
it "returns true" do
1.should == 1
end
end

Use pending instead of describe. If your block is:
context "some other tests" do
it "should do something destructive" do
blah
end
end
You can skip the whole block by:
pending "some other tests" do
it "should do something destructive" do
blah
end
end

describe "GET /blah" do
before(:each) { pending "Feature to be implemented..." }
it { expect(page).to have_button("Submit") }
it { expect(page).to have_content("Blah") }
end

Just to explain what's happening with your code. Including it where you have, it just gets evaluated (and hence run) when the file is loaded during startup. However you need it to be run when the tests run. That's why answers have suggested putting pending (RSpec 2) or skip (RSpec 3) into a before block.

Related

RSpec navigatable it_behaves_like/shared_examples using LSP

I have a legacy project that uses shared_examples feature a lot and it is very inconvenient to navigate between actual specs and shared_examples implementation.
For now, the only way to do it is to search globally within a project using "some example" example name.
RSpec.shared_examples "some example" do |parameter|
let(:something) { parameter }
it "uses the given parameter" do
expect(something).to eq(parameter)
end
end
RSpec.describe SomeClass do
# "some example" has to become *something*
# I can click and navigate to(jump-to-definition)
include_examples "some example", "parameter1"
end
I would like to use LSP/Solargraph for this kind of navigation.
Perhaps anyone did this before and willing to share how they did it?
This turned out simpler than I expected.
Just extract your example name as a string constant and put it somewhere next to RSpec.shared_examples implementation.
# spec/support/shared_examples.rb
# in case you prefer one-liner use:
# RSpec.shared_examples(A_COLLECTION = 'a collection') do
# otherwise:
A_COLLECTION = 'a collection'
RSpec.shared_examples A_COLLECTION do
let(:collection) { described_class.new([7, 2, 4]) }
context 'initialized with 3 items' do
it 'says it has three items' do
expect(collection.size).to eq(3)
end
end
end
# spec/array_spec.rb
RSpec.describe Array do
it_behaves_like A_COLLECTION
end
HINT: In case it doesn't work for you, check .solargraph.yml config which excludes "spec/**/*" from indexing by default.

Handling failures in data driven testing using rspec

I am using rspec to do some data driven testing. My test reads from a csv file, grabs an entry which is inserted into the text box on the page and is then compared to expected text which is also read from the csv file. All this is working as expected, I am able to read and compare without any issues.
Below is my code:
Method for reading csv file:
def user_data
user_data = CSV.read Dir.pwd + '/user_data.csv'
descriptor = user_data.shift
descriptor = descriptor.map { |key| key.to_sym }
user_data.map { |user| Hash[ descriptor.zip(user) ] }
end
Test:
describe "Text box tests" do
before :all do
#homepage = Homepage.new
end
it "should display the correct name" do
visit('http://my test url')
sleep 2
user_data.each do |entry|
#homepage.enter_name(entry[:name])
#homepage.click_go()
sleep 2
begin
expect(page).to have_css("#firstname", text: entry[:expected_name])
end
end
end
end
The problem is with failures. If I have a failure with one of the tests (i.e the expected text is not displayed on the page) then the test stops and all subsequent entries in the csv are not tested. If I put in a rescue after the expect statement like this:
rescue Exception => error
puts error.message
Then the error is logged to the console, however at the end of my test run it says no failures.
So basically I am looking for is, in the event of a failure for my test to keep running(until all entries in the csv have been covered), but for the test run to be marked as failed. Does anyone know how I can achieve this?
Try something like this:
context "when the user is on some page" do
before(:context) { visit('http://example.org/') }
user_data.each do |entry|
it "should display the correct name: #{entry[:name]}" do
#homepage.enter_name(entry[:name])
#homepage.click_go
expect(page).to have_css("#firstname", text: entry[:expected_name])
end
end
end
You will also need to change def user_data to def self.user_data
I would advise mapping over the entries and calling the regular capybara method has_css? instead of the rspec helper method. It would look like this:
results = user_data.map do |entry|
#homepage.enter_name(entry[:name])
#homepage.click_go()
sleep 2
page.has_css?("#firstname", text: entry[:expected_name])
end
expect(results.all?) to be_truthy
if you want to keep track of which ones failed, you cann modify it a bit:
missing_entries = []
user_data.each do |entry|
#homepage.enter_name(entry[:name])
#homepage.click_go()
sleep 2
has_entry = page.has_css?("#firstname", text: entry[:expected_name])
unless has_entry
missing_entries.push entry[:expected_name]
end
end
expect(missing_entries).to be_empty

Writing a Rspec test for an error condition finished with exit

I am writing a command line interface to a Ruby gem and I have this method exit_error, which acts as an exit error point to all validations performed while processing.
def self.exit_error(code,possibilities=[])
puts #errormsgs[code].colorize(:light_red)
if not possibilities.empty? then
puts "It should be:"
possibilities.each{ |p| puts " #{p}".colorize(:light_green) }
end
exit code
end
where #errormsgs is a hash whose keys are the error codes and whose values are the corresponding error messages.
This way I may give users customized error messages writing validations like:
exit_error(101,#commands) if not valid_command? command
where:
#errormsgs[101] => "Invalid command."
#commands = [ :create, :remove, :list ]
and the user typing a wrong command would receive an error message like:
Invalid command.
It should be:
create
remove
list
At the same time, this way I may have bash scripts detecting exactly the error code who caused the exit condition, and this is very important to my gem.
Everything is working fine with this method and this strategy as a whole. But I must confess that I wrote all this without writing tests first. I know, I know... Shame on me!
Now that I am done with the gem, I want to improve my code coverage rate. Everything else was done by the book, writing tests first and code after tests. So, it would be great having tests for these error conditions too.
It happens that I really don't know how to write Rspec tests to this particular situation, when I use exit to interrupt processing. Any suggestions?
Update => This gem is part of a "programming environment" full of bash scripts. Some of these scripts need to know exactly the error condition which interrupted the execution of a command to act accordingly.
For example:
class MyClass
def self.exit_error(code,possibilities=[])
puts #errormsgs[code].colorize(:light_red)
if not possibilities.empty? then
puts "It should be:"
possibilities.each{ |p| puts " #{p}".colorize(:light_green) }
end
exit code
end
end
You could write its rspec to be something like this:
describe 'exit_error' do
let(:errormsgs) { {101: "Invalid command."} }
let(:commands) { [ :create, :remove, :list ] }
context 'exit with success'
before(:each) do
MyClass.errormsgs = errormsgs # example/assuming that you can #errormsgs of the object/class
allow(MyClass).to receive(:exit).with(:some_code).and_return(true)
end
it 'should print commands of failures'
expect(MyClass).to receive(:puts).with(errormsgs[101])
expect(MyClass).to receive(:puts).with("It should be:")
expect(MyClass).to receive(:puts).with(" create")
expect(MyClass).to receive(:puts).with(" remove")
expect(MyClass).to receive(:puts).with(" list")
MyClass.exit_error(101, commands)
end
end
context 'exit with failure'
before(:each) do
MyClass.errormsgs = {} # example/assuming that you can #errormsgs of the object/class
allow(MyClass).to receive(:exit).with(:some_code).and_return(false)
end
# follow the same approach as above for a failure
end
end
Of course this is an initial premise for your specs and might not just work if you copy and paste the code. You will have to do a bit of a reading and refactoring in order to get green signals from rspec.

How to put asserts in Selenium webdriver Ruby script?

I wish to check value on UI with the provided value in script. And on comparing these two, it should display message "test passed" in console.
I have written following code: -
browser.find_element(:xpath,"//*[#id="total"]/tbody/tr/td[4]/span").value.should == "$466,634,599.67"
But it does not display anything on console. What could be required next?
Thanks!
Abhishek
Assertions, eg the .should==, are typically used within a test framework such as RSpec, MiniTest, Cucumber, etc. These test frameworks are designed to have reporting of the assertion's pass or fail result.
Given that you are not using a test framework, you will need to manually handle the output of results.
The most straightforward way would be to drop the assertion part and use an if statement:
element_value = browser.find_element(:xpath,"//*[#id="total"]/tbody/tr/td[4]/span").text
if element_value == "$466,634,599.67"
puts 'Test passed'
else
puts 'Test failed'
end
Note that the puts statements are used to output results to the console (unless you have changed the default output location).
Alternatively, if you do want to use the assertion, you could do:
element_value = browser.find_element(:xpath,"//*[#id="total"]/tbody/tr/td[4]/span").text
element_value.should == "$466,634,599.67"
puts 'Test passed'
In this approach, the assertion will raise an exception if the test fails. The assertion would stop the execution of the code and would therefore not output the 'Test passed' message (as expected). If the test passes, the 'Test passed' message would get outputted.
I use capybara gem for this purpose. It can check almost all front-end possibilities.
Code should look something like this:
describe "User pages" do
subject { page }
describe "index" do
before(:each) do
sign_in user
visit users_path
end
it { expect(page).to have_selector('li', text: user.name) }
end

DRY the SUT up - RSpec and Mocking question

n the .net world, my specs would follow the Arrange, Act, Assert pattern. I'm having trouble replicating that in rspec, because there doesn't appear to be an ability to selectively verify your mocks after the SUT has taken it's action. That, coupled with the fact that EVERY expectation is evaluated at the end of each 'It' block, is causing me to repeat myself in a lot of my specs.
Here's an example of what I'm talking about:
describe 'AmazonImporter' do
before(:each) do
Kernel.**stubs**(:sleep).with(1)
end
# iterates through the amazon categories, and for each one, loads ideas with
# the right response group, upserting ideas as it goes
# then goes through, and fleshes out all of the ideas that only have asins.
describe "find_new_ideas" do
before(:all) do
#xml = File.open(File.expand_path('../amazon_ideas_in_category.xml', __FILE__), 'r') {|f| f.read }
end
before(:each) do
#category = AmazonCategory.new(:name => "name", :amazon_id => 1036682)
#response = Amazon::Ecs::Response.new(#xml)
#response_group = "MostGifted"
#asin = 'B002EL2WQI'
#request_hash = {:operation => "BrowseNodeLookup", :browse_node_id => #category.amazon_id,
:response_group => #response_group}
Amazon::Ecs.**expects**(:send_request).with(has_entries(#request_hash)).returns(#response)
GiftIdea.expects(:first).with(has_entries({:site_key => #asin})).returns(nil)
GiftIdea.any_instance.expects(:save)
end
it "sleeps for 1 second after each amazon request" do
Kernel.**expects**(:sleep).with(1)
AmazonImporter.new.find_new_ideas(#category, #response_group)
end
it "loads the ideas for the given response group from amazon" do
Amazon::Ecs.**expects**(:send_request).
with(has_entries(#request_hash)).
returns(#response)
**AmazonImporter.new.find_new_ideas(#category, #response_group)**
end
it "tries to load those ideas from repository" do
GiftIdea.expects(:first).with(has_entries({:site_key => #asin}))
**AmazonImporter.new.find_new_ideas(#category, #response_group)**
end
In this partial example, I'm testing the find_new_ideas method. But I have to call it for each spec (the full spec has 9 assertion blocks). I further have to duplicate the mock setup so that it's stubbed in the before block, but individually expected in the it/assertion block. I'm duplicating or nearly duplicating a ton of code here. I think it's even worse than the highlighting indicates, because a lot of those globals are only defined separately so that they can be consumed by an 'expects' test later on. Is there a better way I'm not seeing yet?
(SUT = System Under Test. Not sure if that's what everyone calls it, or just alt.net folks)
You can use shared example groups to reduce duplication:
shared_examples_for "any pizza" do
it "tastes really good" do
#pizza.should taste_really_good
end
it "is available by the slice" do
#pizza.should be_available_by_the_slice
end
end
describe "New York style thin crust pizza" do
before(:each) do
#pizza = Pizza.new(:region => 'New York' , :style => 'thin crust' )
end
it_behaves_like "any pizza"
it "has a really great sauce" do
#pizza.should have_a_really_great_sauce
end
end
Another technique is to use macros, which is handy if you need similar specs in different classes.
Note: the example above is borrowed from The RSpec Book, Chapter 12.
you can separate them using "context" if that helps...
https://github.com/dchelimsky/rspec/wiki/faq

Resources