RSpec test that a class method calls an instance method - ruby-on-rails

I'm looking to test that a class method calls a specific instance method. Is there any way to do this? This is the best I've got, but it fails.
describe '#foo' do
let(:job) { create :job }
it 'calls job.bar' do
job.should_receive(:bar)
Job.foo
end
end
I need to be sure that the right instance of job is called, not just any instance. I appreciate any help.

You can use stubs on the method by which .foo gets the instance.
For instance:
describe '.foo' do
let(:job) { create :job }
it 'calls job.bar' do
Job.stub(:find).and_return job
job.should_receive(:bar)
Job.foo
end
end
What this does is ensures that the instance that you expect to have methods called on is the one that actually gets used by .foo.
You can add expectations or argument matchers to this, so:
Job.should_receive(:find).with(job.id).and_return(job)

Related

How to test non static method was being called by other method using Rspec

I'm trying to test a method being called by another method.
I don't want to test what the other method do, because this is a separate unit test.
so let's say I have something like:
class MyService
def method_a
a = 1
b = method_b
return a + b
end
def method_b
return 2
end
end
Now, I want to test method_a - I want to verify that method_b was executed.
I know that this should work if the methods were static. But in my case, it's not static.
allow(MyService).to receive(:method_b)
I keep getting this error:
MyService does not implement method_b
And I understand that's because the method is not static, but I can't find anything in the documentation that fit my use case.
I think main problem problem is that you expecting for class method to be called and not instance
describe MyService do
it "should call method_b" do
expect(subject).to receive(:method_b).and_return(2)
subject.method_a
end
end
# P.S. it's the same as:
describe MyService do
it "should call method_b" do
service = MyService.new # instead of MyService.new you can also write described_class.new
expect(service).to receive(:method_b).and_return(2)
service.method_a
end
end

RSpec - mock a private class method call inside a request spec?

This is my class
class MyClass
def run
to_be_mocked("arg")
## etc
end
private
def to_be_mocked(arg)
# implementation
end
end
and my Controller, which is what I am writing the request specs for, call this class.
This are my request specs:
context "Some context" do
context "some sub context" do
before :each do
allow(MyClass). to receive(: to_be_mocked).with(account.url).and_return(false)
end
it "responds with a 200" do
do_request
expect(JSON.parse(response.body)["field"]).to eq true
expect(response.status).to eq 200
end
end
However my mocking fails with an MyClass does not implement: to_be_mocked
Already tried removing the private keyword, but got the same results.
What am I missing here?
You're mocking on the class, which is how you mock you "static" class-level methods. For example, if your method was def self.foo and you called it via MyClass.foo, then allow(MyClass) is the way to go.
Your method is not a class-level method, it's an instance method. You invoke it by first creating an instead of MyClass and then calling the method on that instance. You need to use allow_any_instance_of to mock the method for all future instances of the class:
allow_any_instance_of(MyClass).to receive(....)

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: How to properly test class method that loops through a collection / calls instance method

Consider the following class and class method:
class Foo < ActiveRecord::Base
scope :active, -> { where(deleted: false) }
class << self
def some_class_method
active.each do |foo|
foo.some_instance_method
end
end
end
end
what is the best practice to test such a method in RSpec? What I have learned thus far suggests that I should make sure that each active instance of Foo receives a call to some_instance_method, but if I were to make an expectation regarding Foo.some_class_method, to my knowledge I cannot assert a nested expectation about any instance of Foo.
Any help would be appreciated!!
The approach I would take is to separately test some_instance_method, like:
it 'should return some value' do
expect(foo.some_instance_method).to eq('some value')
end
You could then run the class method and test that the transformations happened as expected:
context 'Foo#some_class_method' do
it 'should have some effect' do
expect(some_comparison_variable).to eq('some_before_state')
Foo.some_class_method
expect(some_comparison_variable).to eq('some_after_state')
end
end

Testing instance variable assignment in constructor (RSpec)

I would like to test simple constructor:
def initialize(parameters_hash)
#parameters_hash = parameters_hash
end
Do you think that approach:
describe '.new' do
let(:parameters_hash) { {} }
it 'assigns input to #parameters_hash instance variable' do
expect(subject.instance_variable_get('#parameters_hash')).to eq(parameters_hash)
end
end
is proper. Maybe you know some other solutions.
Rspec already implements the assigns helper see here for a controller that does exactly what you need.
If you need something like that for a model, consider using an attr_reader, and test that
expect(subject.parameters_hash).to eq({})

Resources