undefined method instance_double for RSpec::Mocks::ExampleMethods - ruby-on-rails

I have a test case like this:
describe WorkCardsController do
it "something" do
work_card = instance_double(WorkCard, {:started?=>true} )
#some more code
end
end
When I run RSpec, I get an error:
undefined method 'instance_double' for #<Rspec::Core::ExampleGroup::Nested_1::Nested_8::Nested_3:0x007f0788b98778>
According to http://rubydoc.info/github/rspec/rspec-mocks/RSpec/Mocks/ExampleMethods this method exists. So I tried to access it directly by:
describe WorkCardsController do
it "something" do
work_card = RSpec::Mocks::ExampleMethods::instance_double(WorkCard, {:started?=>true} )
#some more code
end
end
And then I got a very surprising error:
undefined method 'instance_double' for Rspec::Mocks::ExampleMEthods:Module
which is contrary to the documentation I linked above.
What am I missing?

From the documentation you pointed to:
Mix this in to your test context (such as a test framework base class) to use rspec-mocks with your test framework.
Try to include it into your code:
include RSpec::Mocks::ExampleMethods
Your direct approach failed, because calling
RSpec::Mocks::ExampleMethods::instance_double(...)
expects that the method was declared as a class method:
def self.instance_double(...)
but it has been declared as an instance method :
def instance_double(...)

Related

Calling rspec methods from different file

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

How do you stub and test a helper that invokes a different method depending on the object class passed to it?

I've got this helper which I'm trying to write tests for in Minitest. The helper calls another method depending on the object class I'm passing as an argument, like so:
def label_for(object)
status = object&.status
case object.class.name
when "Subscription"
class_for_subscription_status(status)
when "Payment"
class_for_payment_status(status)
when "Purchase"
class_for_purchase_status(status)
when "Invoice"
class_for_invoice_status(status)
when "Ticket"
class_for_ticket_status(status)
end
Each individual method is already tested somewhere else, so I just need to test that if I pass a class Subscription object to label_for, it will invoke class_for_subscription_status(status) and not something else.
This is the test I've come up with, but I get NoMethodError: undefined method ``class_for_subscription_status' for #<AuxiliariesHelperTest errors.
test "#label_for(object) should invoke the right helper if object is of class Subscription" do
AuxiliariesHelperTest.any_instance.stubs(:label_for).with(subscriptions(:user)).returns(:class_for_subscription_status)
assert_equal class_for_subscription_status(subscriptions(:user).status), label_for(subscriptions(:user))
end
What am I doing wrong?
Could you add the whole classes? Is a little bit hard to guess with just this snippet.
One of the problems I see is that you are stubbing a method from the AuxiliariesHelperTest class, instead of the AuxiliariesHelper class.
Another possible issue is that your helper seems to be a module and not a class, and you should include the helper in your test file. Or your test class should inherit from ActionView::TestCase. Something like this might help:
class AuxiliariesHelperTest < ActionView::TestCase
include AuxiliariesHelper
test "#label_for(object) should invoke the right helper if object is of class Subscription" do
AuxiliariesHelper.any_instance.stubs(:label_for).with(subscriptions(:user)).returns(:class_for_subscription_status)
assert_equal class_for_subscription_status(subscriptions(:user).status), label_for(subscriptions(:user))
end
end
Although in my opinion, you should not stub the method, but expect that the correct method is called:
class AuxiliariesHelperTest < ActionView::TestCase
include AuxiliariesHelper
test "#label_for(object) should invoke the right helper if object is of class Subscription" do
AuxiliariesHelper.any_instance.expects(:label_for).with(subscriptions(:user).status)
label_for(subscriptions(:user))
end
end

Rspec "NoMethodError" from nested module

I'm running into a weird error:
Class:
module AnimalSanctuary
module AnimalInspector
class AnimalPicker
def initialize(number_of_animals, ids)
#number_of_animals = number_of_animals
#ids = ids
end
...
def pick_animals(animal)
end
end
end
test:
require 'rails_helper'
RSpec.describe AnimalSanctuary::AnimalInspector::AnimalPicker do
describe ".pick_animals" do
context "pick an available animal" do
it "returns animal name" do
expect(AnimalSanctuary::AnimalInspector::AnimalPicker.pick_animals("Dog")).to eq("Dog")
end
end
end
end
I get the following error:
NoMethodError:
undefined method `pick_animals' for AnimalSanctuary::AnimalInspector::AnimalPicker:Class
Rspec calls the class but not the method which has stumped me. Am I doing something wrong?
The definition of pick_animals is an instance method.
To call it, you will need to instantiate an object of the class using the new method as shown below. I have passed in random values to your initializer (1, [1,2]) however you can set them as you like.:
number_of_animals = 1
ids = [1,2]
AnimalSanctuary::AnimalInspector::AnimalPicker.new(number_of_animals, ids).pick_animals("Dog")
Otherwise, to call it the way you are calling it, you will need to redefine it as a class method by using self.pick_animals as shown below:
module AnimalSanctuary
module AnimalInspector
class AnimalPicker
...
def self.pick_animals(animal)
end
end
end
yeah pick_animals is an instance method.
you can use the following in your rspec
expect_any_instance_of(nimalSanctuary::AnimalInspector::AnimalPicker).to receive(:pick_animals).with("dogs").to_eq("Dog")
Hope this helps

Static method in Unittest not found - NoMethodError - Ruby

I have some unit tests which try to test my API:
class ClassToBeTested
def self.something_first
# Do Something
end
def self.something_second
# Do Something
end
end
I call them in the testing class then as following:
class MyTest < ActionDispatch::IntegrationTest
test 'should get something_first' do
assert ClassToBeTested.something_first
end
test 'should get something_second' do
assert ClassToBeTested.something_second
end
end
Which ends up throwing the following error:
Error: MyTest#test_should_get_something_first: NoMethodError:
undefined method something_first' for ClassToBeTested
test/services/my_test.rb:89:inblock in '
bin/rails test test/services/my_test.rb:88
I tried around a lot but I can't find what the issue is.
The Issue I was faced was that a Library I was using had a class with the same name.
So my Unittest was calling this other class and not the class I defined, to solve this I added:
load 'ClassToBeTested.rb' in the header of the testing class.
A cleaner way probably is to define the ClassToBeTested in a Module and use the namespace to call it.

NameError: undefined local variable or method `desired_preferences'

I have created a module with a method
module Adding_preferences
def desired_preferences
#preference = %w(motabilitySpecialist newCars bodyshop filter8 filter7).each do |selection|
#browser.label(:for, selection ).click
end
end
end
I have included this module into a class:
class Pages
include Adding_preferences
attr_accessor :browser, :preference
def initialize
#browser = Watir::Browser.new :ff
end
end
World do
Pages.new
end
I am calling this method in a Cucumber scenario
When /^I select a desired preference$/ do
desired_preferences
end
But at runtime I receive an error, "NameError: undefined local variable or method `desired_preferences'". Where am i going wrong?
When you include a module to a class you can use this method in the instance methods of this class. You cant call the included method in a View that displays the data from the model that includes the module. For me it looks like you just dont use the desired_preferences method in an instance method.
Please show us the peace of code you try to call the method if this still doesnt help you out.
// The naming of the Module is not conventional. You should call it module AddingPreferences isntead ofmodule Adding_preferences and the file should be named adding_preferences.rb then try to include AddingPreferences
It's a good idea for you to spend some time getting more familiar with Ruby's Class/Module/Object/Method inheritance model, because the way you're structuring your code there is a little bit messy.
However, a simple thing to try (and I'm not going to guarantee that it will work flawlessly) is the following modifications:
Assign your instantiated Pages class to a class instance variable:
World do
#page = Pages.new
end
...and then use that instance variable in your step definition...
When /^I select a desired preference$/ do
#page.desired_preferences
end
I hope that helps!

Resources