I am just trying to create a simple rspec method that takes an object as an argument. I can do something like the following:
def check_it(p)
before { visit p.full_path }
page.should have_title("sample title")
p.children.published.each do |pp|
check_it(pp)
end
end
so far I have not even figured out where I can put this code to avoid:
undefined method `check_it'
error, unless I put it with the other rails helpers at which point I get an
undefined method `before' for main:Object (NoMethodError)
Some help getting off the ground would be greatly appreciated.
You can add it in various places within the rspec file outside of the example. E.g.:
def check_it(p); puts p; end
describe 'foo' do
def check_it2(p); puts p; end
context 'bar' do
def check_it3(p); puts p; end
it 'does something' do
check_it 'hello'
check_it2 'world'
check_it3 'wide'
end
end
end
There are also ways to add it outside of the rspec file, e.g. put it in a file in spec/support and include it into the target rspec file.
Don't know how other people do it but I add a directory to spec and call it support because spec_helper includes this line:
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Meaning anything in the support directory will be included in each run.
So you can just place this specific method directly in a file in spec/support and it will be callable or you can include it in a module and then include that module where you need it.
Related
I am trying to write a class in my code to wrap some of the RSpec calls. However, whenever I try to access rspec things, my class simply doesn't see the methods.
I have the following file defined in spec/support/helper.rb
require 'rspec/mocks/standalone'
module A
class Helper
def wrap_expect(dbl, func, args, ret)
expect(dbl).to receive(func).with(args).and_return(ret)
end
end
end
I get a NoMethodError: undefined method 'expect', despite requiring the correct module. Note that if I put calls to rspec functions before the module, everything is found correctly.
I've tried adding the following like to my spec_helper.rb:
config.requires << 'rspec/mocks/standalone'
But to no avail.
I managed to use class variables in my class and passing the functions through from the global context, but that solution seems quite extreme. Also I was able to pass in the test context itself and storing it, but I'd rather not have to do that either.
expect functions by default is associated with only rspec-core methods like it before . If you need to have expect inside a method, you can try adding the Rspec matcher class in the helper file.
include RSpec::Matchers
that error because the self which call expect is not the current rspec context RSpec::ExampleGroups, you could check by log the self
module A
class Helper
def wrap_expect(dbl, func, args, ret)
puts self
expect(dbl).to receive(func).with(args).and_return(ret)
end
end
end
# test case
A::Helper.new.wrap_expect(...) # log self: A::Helper
so obviously, A::Helper does not support expect
now you have 2 options to build a helper: (1) a module or (2) a class which init with the current context of test cases:
(1)
module WrapHelper
def wrap_expect(...)
puts self # RSpec::ExampleGroups::...
expect(...).to receive(...)...
end
end
# test case
RSpec.describe StackOverFlow, type: :model do
include WrapHelper
it "...." do
wrap_expect(...) # call directly
end
end
(2)
class WrapHelper
def initialize(spec)
#spec = spec
end
def wrap_expect(...)
puts #spec # RSpec::ExampleGroups::...
#spec.expect(...).to #spec.receive(...)...
end
end
# test case
RSpec.describe StackOverFlow, type: :model do
let!(:helper) {WrapHelper.new(self)}
it "...." do
helper.wrap_expect(...)
end
end
I have an option defined in application config. My class I want to test is defined in a gem (not written by me). I want to reopen the class:
Myclass.class_eval do
if Rails.application.config.myoption=='value1'
# some code
def self.method1
end
else
# another code
def self.method2
end
end
end
I want to test this code using RSpec 3:
# myclass_spec.rb
require "rails_helper"
RSpec.describe "My class" do
allow(Rails.application.config).to receive(:myoption).and_return('value1')
context 'in taxon' do
it 'something' do
expect(Myclass).to respond_to(:method1)
end
end
end
How to stub application config value before running the code which reopens a class.
Wow, this have been here for a long time, but in my case what I did was:
allow(Rails.configuration.your_config)
.to receive(:[])
.with(:your_key)
.and_return('your desired return')
Specs passing and config values stubed correctly. =)
Now, the other thing is about your implementation, I think it would be better if you defined both methods and inside from a run or something you decided wich one to execute. Something like this:
class YourClass
extend self
def run
Rails.application.config[:your_option] == 'value' ? first_method : second_method
end
def first_method
# some code
end
def second_method
# another code
end
end
Hope this helps.
Edit: Oh yeah, my bad, I based my answer on this one.
This is my module. I like to test method load_csv
I referred this example Example Link
and wrote this code. Below is the module Code
require 'csv'
module DummyModule
class Test
def load_csv(filename)
CSV.read(filename, :row_sep => "\r", :col_sep => "\t")
end
end
end
this is my Rspec
require 'spec_helper'
describe DummyModule do
let(:data) { "title\tsurname\tfirstname\rtitle2\tsurname2\tfirstname2\r" }
let(:result) { [["title", "surname", "firstname"], ["title2", "surname2", "firstname2"]] }
before(:each) do
#attribute_validator = TestAttributeValidator.new
end
it "should parse file contents and return a result" do
puts data.inspect
puts result.inspect
File.any_instance.stubs(:open).with("filename","rb") { StringIO.new(data) }
#attribute_validator.load_csv("filename").should eq(result)
end
end
class TestAttributeValidator
include DummyModule
end
It gives me this error
DummyModule should parse file contents and return a result
Failure/Error: #attribute_validator.load_csv("filename").should eq(result)
NoMethodError:
undefined method `load_csv' for #<TestAttributeValidator:0xd0befd>
# ./spec/extras/dummy_module_spec.rb:15:in `(root)'
Pls Help
You probably do not want your
class Test
inside your module definition. Like this the following would work:
#attribute_validator_tester = TestAttributeValidator::Test.new
#attribute_validator_tester.respond_to? 'load_csv'
=> true
but that is probably not what you intended. Including a module into a class will add all the 'features' of the module (that is all the methods, but also constants, and classes) to the class the module is included in. In your example you added the class Test to the namespace of class TestAttributeValidator and the instances of this class would have the method load_csvyou desire.
Just omit the class definition inside your module and all will be well.
(Adding another answer as this is really another question)
Googling for Errno::ENOENT leads to this answer, but that should hardly be necessary as the error message is really telling, your file was not found. Since you stubbed for "filename" it should be found if the version of CSV you are using still uses open to open the file (which the current ruby CSV reader seems to do, see the source) then it actually should work.
However depending on your version of ruby the CSV library might add some more options, the version I referenced merges universal_newline: false to the options for open, so your stub would not have all the parameters it expects and forward your call to the "regular" method which does not find your "filename". You should check your exact version of ruby and stub accordingly.
That is probably part of the legacy that comes with such a dynamic language as ruby :-)
How is it that rspec feature tests implicitly know to use methods such as find, within, and fill_in from the page object?
I've written a helper class for some of my rspec tests and wanted to use those methods, and realized that I needed to pass the page object into the method, and then use page.find and the like.
RSpec achieves this by including Capybara::DSL in those cases where it wants those methods available. The module is pretty elegant, if you want to take a look at https://github.com/jnicklas/capybara/blob/f83edc2a515a3a4fd80eef090734d14de76580d3/lib/capybara/dsl.rb
suppose you want to include the following module:
module MailerMacros
def last_email
ActionMailer::Base.deliveries.last
end
def reset_email
ActionMailer::Base.deliveries = []
end
end
to include them, just call config.include(MailerMacros), like this:
RSpec.configure do |config|
config.include(MailerMacros)
end
now, you should be able to call reset_email() & last_email instead of MailerMacros::reset_email().
Im trying to define some controller macros for Rspec. Im using rails 3 and have my macros defined in spec/support/macros/controller_macros.rb, that file looks like this:
module ControllerMacros
def self.login_admin
#code
end
end
in my spec helper I have:
config.include(ControllerMacros, :type => :controller)
So in my controller spec i just call login_admin in my admin tests but when ever i use the method i get
undefined local variable or method `login_admin' for #<Class:0xb6de4854> (NameError)
At first I assumed that controller_macros.rb wasn't being included but when I added a "puts" to the file but that showed the file was at least being executed.
I can't see anything wrong with my setup and copying the login_admin method into the describe block works fine so im not sure whats wrong with it.
Maybe I am late to that, but for new comers.
Here is a good examples of using macros:
http://osmose.6spot.com.br/2011/01/rails-resource-routing-spec-w-rspec/
when you include a module it's methods are visible inside examples.
But when you extend the module, it's methods are only visible outside examples.
It gives you ways to compose your macros for each situation.
Try
ControllerMacros.login_admin
or remove self from the method definition.
One line answer: Remove self from the method definition
Why? The methods of included modules are available in RSpec examples
The login_admin method defined in ControllerMacros will be available in your RSpec example as login_admin
To Be Specific:
Rewrite spec/support/macros/controller_macros.rb as
module ControllerMacros
def login_admin
#code
end
end
Then tell Rspec to include the Macros
config.include(ControllerMacros, :type => :controller)