Static method in Unittest not found - NoMethodError - Ruby - ruby-on-rails

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.

Related

Use anonymous class generated by struct in ruby tests

So, here we have a file with struct,
module CoreDomain
Corporation = Struct.new(...)
end
and we have such a test file,
require 'test_helper'
module CoreDomain
class CorporationTest < ActiveSupport::TestCase
def test_corporation_struct_creation
corp_struct = CoreDomain::Corporation.new(...)
assert_equal ..., ...
end
end
end
when I trying to execute the test I get this error.
NameError: uninitialized constant CoreDomain::Corporation
Question - where I am getting wrong?
What I think is going actually going on here is that you're fooling the autoloader.
Since your test is nested inside module CoreDomain when you get to CoreDomain::Corporation.new(...) it won't trigger the autoloader to start looking for the CoreDomain constant. The classic autoloader worked by hacking its way onto Object.const_missing so was very prone to these kind of errors.
The solution is to just reference the constant before you reopen the module:
require 'test_helper'
CoreDomain::Corporation # take that you stupid autoloader!
module CoreDomain
class CorporationTest < ActiveSupport::TestCase
def test_corporation_struct_creation
corp_struct = Corporation.new(...)
assert_equal ..., ...
end
end
end
Or just remove the test class from the module.
Maybe there was some misunderstanding, but all I need to do is to add this line
require_relative '../../core/domain/corporation.rb'
to the top of test_corporation.rb file

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

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

How to test Rails model associations

Trying to test a module. It works when executed in rails console, but not when written as a test. Suppose the following:
MyModel
a) has_many :my_other_model
MyOtherModel
a) belongs to :my_model
Module example:
module MyModule
def self.doit
mine = MyModel.first
mine.my_other_models.create!(attribute: 'Me')
end
end
Now test:
require 'test_helper'
class MyModuleTest < ActiveSupport::TestCase
test "should work" do
assert MyModule.doit
end
end
Returns:
NoMethodError: NoMethodError: undefined method `my_other_models' for nil:NilClass
Now try the same thing in the console:
rails c
MyModule.doit
Works just fine. But why not as a test?
Your test database is empty when you run this test, so calling MyModel.first is going to return nil, then you try to chain an unknown method to nil. What you'll probably want for your test suite is a fixture, which is just sample data. For now, you you can just create the first instance to get the test to work.
test "should work" do
MyModel.create #assuming the model is not validated
assert MyModule.doit
end
You could also refactor your module. Adding if mine will only try to create the other models if mine is not nil. That would get the test to pass, but negates the purpose of your test.
def self.doit
mine = MyModel.first
mine.my_other_models.create!(attribute: 'Me') if mine
end

undefined method instance_double for RSpec::Mocks::ExampleMethods

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(...)

Resources