Namespace issue in Rspec while using the let() helper function - ruby

I'm having an issue with using the let function provided by rspec:
In app/spec/class_spec.rb:
require 'spec_helper'
module App
describe Class do
let(:instance) {Class.new('param')}
describe "#method" do
it "does something" do
instance.method(...)
# clever test code
end
.
.
.
end
I've been following the RSpec book, and according to its examples (which worked through!) let should give me access to the variable instance for the rest of the 'describe Class' block. But I get the error:
Uninitialized constant App::instance
I also tried adding this code to no avail:
before :all do
instance
end
What am I doing wrong?

Instead of
module App
describe Class do
just use:
describe App::Class
and everything should be fine
hint: instead let(:instance) {Class.new('param')} you could write let(:instance) {described_class.new('param')}. It's more clever.

Related

How can two specs share the same "it" block?

I have two tests that are very similar. In fact, both tests should produce the same results, but for different inputs. Each needs its own before block but in the interest of DRY I'd like them to share the same it block.
Is that even possible? If so, how?
Shared Examples in Rspec are designed to be used for this purpose. You can keep common it blocks inside a shared example and include them in describe or context blocks.
Simplest example of shared_examples would be,
RSpec.shared_examples "unauthorized_response_examples" do
it { expect(subject).to respond_with(403) }
it { expect(json['message']).to eq(I18n.t("unauthorized")) }
end
And inside your controller specs whenever you need to check unauthorized response you can include examples like,
...
include_examples "unauthorized_response_examples"
Also, you can pass on parameters, action names and controller names and have before(:each|:all) hooks and nested contexts or describe.
For more, you can look at rspec documentation.
Helper methods. (Excuse the horribleness of the example. Would have been better if you'd posted yours :P)
describe "soup" do
def soup_is_salty # helper method! \o/
soup.add(:meat)
soup.add(:egg)
soup.cook
soup.salty?
end
describe "with carrot" do
before(:all) do
soup.add(:carrot)
end
it "should be salty" do
soup_is_salty # get help from helper method! \o/
end
end
describe "soup with potato" do
before(:all) do
soup.add(:potato)
end
it "should be salty" do
soup_is_salty # get help from helper method! \o/
end
end
end
Take the block and create and external method
for example I have some tests that require me to login to my app. So I have a helper.rb file that I include in each spec and that contains a "login" block. Then in each test I can just call login

How to check whether a variable is an instance of a module's subclass using rspec?

I have a class structure that looks like this:
module MyModule
class MyOuterClass
class MyInnerClass
end
end
end
I'm trying to make sure that a variable was correctly instantiated as a MyInnerClass using Rspec. printing the type of the class, it was MyModule::MyOuterClass::MyInnerClass. However, if I try to run the line
expect{#instance_of_MyInnerClass}.to be_an_instance_of(MyModule::MyOuterClass::MyInnerClass)
I get the error "You must pass an argument rather than a block to use the provided matcher." Additionally, the classes are in another location, so I can't just check
[...] be_an_instance_of(MyInnerClass)
Rspec complains that MyInnerClass is an uninitialized constant. So, I would like to ask how to verify that a variable is an instance of MyInnerClass using RSpec.
Don't Pass a Block
Rspec 3.x uses an expect method rather than a block syntax (see RSpec 3 Expectations 3.0). To get your spec to pass, and clean it up, you can use the following:
module MyModule
class MyOuterClass
class MyInnerClass
end
end
end
describe MyModule::MyOuterClass::MyInnerClass do
it "is correctly instantiated" do
expect(subject).to be_an_instance_of MyModule::MyOuterClass::MyInnerClass
end
end
Note the use of the implicit subject, passed as an argument to #expect. You can certainly pass other local or instance variables instead, but in this case subject is already defined for you as MyModule::MyOuterClass::MyInnerClass.new.
Most of us are using the preferred Rspec syntax, so it would be:
expect(#instance_of_MyInnerClass).to be_a MyInnerClass

can I have RSpec without a class for methods

I'm just writing some algorithm methods that I don't want to put in a class. So I just put them in my ruby file.
But I cant figure out how to write test or more specifically use describe :xxx since I dont' have a class name to put after the main describe. Any ideas?
You can put any string after the describe statement:
describe "Something You Want To Test" do
# Your specs here
end

Cucumber/Capybara - Using RSpec matchers with a "Page Object" pattern

I'm currently refactoring a whole load of cucumber tests to use a "Page Object" pattern, but I'm having a lot of problems using the RSpec matchers.
The existing step I have is as follows:
Then /^I should (not )?see the following alerts:$/ do |negate, alerts|
expectation = negate ? :should_not : :should
within(ALERT_TABLE_ID) do
alerts.hashes.each do |alert|
page.send(expectation, have_content(alert["Original ID"]))
end
end
end
My refactored step is:
Then /^I should (not )?see the following alerts:$/ do |negate, alerts|
expectation = negate ? :should_not : :should
#alert_reporting_panel = AlertReportingPanel.new(Capybara.current_session)
#alert_reporting_panel.verify_contents expectation, alerts
end
And my Panel Object is:
class AlertReportingPanel
def initialize(session)
#session = session
end
def verify_contents(expectation, alerts)
#session.within(ALERT_TABLE_ID) do
alerts.hashes.each do |alert|
#session.send(expectation, have_content(alert["Original ID"]))
end
end
end
end
Unfortunately, I get undefined method 'have_contents' for #<AlertReportingPanel:0x3f0faf8> (NoMethodError).
I have tried adding require 'rspec' to the top of the class and also tried fully qualifying the have-content method thus: Capybara::RSpecMatchers::HaveMatcher.have_content, but I just get uninitialized constant Capybara::RSpecMatchers (NameError).
I'm pretty new to Ruby and I'm sure this is trivial to fix... but I just can't seem to work it out for myself.
Please help. Thankyou.
This was a while back so I'm guessing you may have your answer by now but here goes.
You need to include the necessary modules in order bring in and have access to the likes of *have_content*. So your Panel Object would look like:
class AlertReportingPanel
include Capybara::DSL
include Capybara::Node::Matchers
include RSpec::Matchers
def initialize... etc
Instead of writing your own Page Object system you could try using SitePrism
I'm a little biased (I wrote that gem) but it might make life easier for you.

Rspec: when the matcher fails

I have a Rails project and use RSpec as a testing framework. What I need is to subscribe to the event when some matcher fails, e.g. I got this:
true.should be_false
I want to do some action on every fail. Is this functionality provided by the RSpec?
You can monkey-patch this behavior into RSpec::Core::Example class:
require 'spec_helper'
class RSpec::Core::Example
def failed?
!#exception.nil?
end
end
describe "my_tested_things" do
...
end
Then you can ensure it will run your desired code after all failing matches:
after(:each) do
run_my_code if example.failed?
end
Check out the hooks, not certain it will help but where it passes example in to the block (in the docs) you may be able to get the result...
https://www.relishapp.com/rspec/rspec-core/v/2-0/docs/hooks

Resources