I am really new to Rspec and tried to find my answer, but it keeps on pointing me to use stub_chain, but it seems like it is deprecated on Rspec3. I have the following I am trying to stub:
active_automation = Client.automation_active_status.new_client
Where Client is my model and automation_active_status is the following in my Client model
scope :automation_active_status, -> { where(automation_status: true) }
new_client is an attribute I want to call to further filter my result
I tried to implement stub_chain but that did not work. My goal is to get the following to work:
Client.any_instance( black_box_I_can_not_figure_out ).returns[something]
Thank you.
I believe you might be looking for allow and receive_message_chain.
allow(Client).to receive_message_chain(:automation_active_status, :new_client) { [thing_to_return] }
This will stub the methods allowed it, and return whatever comes out of the block you pass it. Hope it helps.
Client.stub_chain(:automation_active_status, :new_client).and_return([thing-to-return]) should get you where you're trying to get.
Additionally, any_instance should be used on instances of a class. For instance, Client.first would be an instance, but Client is the class (and you can stub directly on it).
Related
Hey Folks!
I'm researching a way to mock a private class method.
Before I we begin I'd like to give you some context. Firstly I am not doing this on production, initially I tried to mock it (the private class method) and decided against it, partly because I realised it was just wrong to do so and partly because I couldn't figure out how to do it 😁.
On that note some part of me felt that, somewhat ironically, the right way was a cop out 🙈. So now I am trying to satiate the need for knowledge 😋.
Here it goes.
So, I am testing a controller for success (status 200), which depends on the response of a class method in a module maintained by another party. This method in turn does some validation in a private class method contained in that same module. In an attempt to skip over this validation and get straight to the part where I return the data and in the process spare my testing server from incessant creation of Factory models...
I tried to:
allow(TheOtherModule.Class).to receive(:this_private_class_method).and_return(whatever)
To my great disappointment I found such things cannot be achieved like that, allow_any_instance_of was of no help either. This led to some desperate attempts like trying to:
allow(ThisModule.Class).to receive(:send).with('this_private_class_method').and_return(whatever)
...as well as some more elaborate ones like putting a converter of methods in before and after like so:
saved_private_methods = ThisModule.Class.private_methods
before :each do
ThisModule.Class.class_eval { public *saved_private_methods }
end
after :each do
ThisModule.Class.class_eval { private *saved_private_methods }
end
which just failed spectacularly because I copied it and class_eval, somewhat counterintuitively doesn't target class methods, the result of which is that the methods would be found by private_methods...uhm...method but once the conversion was attempted they would not be evaluated, so instead you have to use...
# Oh and dropped this it's overkill
# saved_private_methods = ThisModule.Class.private_methods
before :each do
ThisModule.Class.instance_eval { public :this_private_class_method }
end
after :each do
ThisModule.Class.instance_eval { private :this_private_class_method }
end
...which worked beautifully at what it was supposed to do except that rspec allow still wouldn't pick it up...
So now I am turning to the Bastion of knowledge that is SO in hopes of finding a way it could be done or at least a definite answer of why it cannot.
Either this doesn't exist or i am looking at this the wrong way.
In rspec, I want to stub a method/attribute of all the instances of a class but only if that instance follows a certain condition, for example:
the following code will stub all posts with given comments:
Post.any_instance.stub(:comments).and_return([comment1, comment2])
but I only want to stub comments if the post is published, otherwise i want a blank comments array.
Is there any way I can do something like this:
Post.any_instance.stub(:comments) do |post|
post.published ? [comment1,comment2] : []
end
I have seen solutions where you send an argument to the stubbed method and based on argument value you can return different values, but that's not the case here.
The code you've included should work fine. Stubbing with a block is documented in https://relishapp.com/rspec/rspec-mocks/v/3-3/docs/old-syntax/any-instance#block-implementation-is-passed-the-receiver-as-first-arg, although it's deprecated now in favor of the new methods described at https://relishapp.com/rspec/rspec-mocks/v/3-3/docs/working-with-legacy-code/any-instance
I have created a module in order to implement a common controller action: order
When I define the method I want to check if the controller that has included the module, responds to a specific method (authorize_respond).
How can I achieve that?
Find below my current implementation that doesn't work (never calls the method authorize_ordering).
def order
send(:authorize_ordering) if self.respond_to?(:authorize_ordering)
ordering = params[:ordering]
...
end
Embarrassing, never mind.
Method authorize_ordering was protected. Being public works as expected.
I'm a newbie and I'm wondering if my app is going to fail is a near future because I don't understand all subtleties of Rails. So I prefer to ask you :-)
I have a User and a Product model, and I want to create a method that could be used like that :
#user.take!(product)
So I wrote in my User model the following line :
def take!(product)
product.owner = self
end
But if I do that in the private section of my model, it doesn't work. And if I do that in the public section, I don't know if it's recommended. I'm asking myself if it would be better to do something like that in a controller, or in a helper...
Can you enlighten me ?
Writing public methods is fine if they need to be public, it's not a hanging offence or anything like that. The method you describe shouldn't be on the user though - there's no need to put product logic inside the user model, and it's definitely bad to change the product by passing it into a user method. It's also a very short method and so there isn't really very much to be gained by putting it into a method - it just means that if I see take! then I have to go and find where it's defined in order to understand it. You should also only use ! at the end of methods that either might raise an exception or alter the object they are called on.
Putting this logic in the controller would be fine and much clearer, but in general there's nothing wrong with public methods if they can't be private.
So, I have a controller nested within 2 others
here's an example route
products/123/conditions/321/inventories/121
and the controllers are nested like this as well, so I'm trying to figure out what to stub out in my tests.
Product.should_receive(:find) does not get called. I'm wondering what will be the first thing called so I can begin to stub it.
I could find this out if I had a way to take a class and listen to all methods called on it. Is there a way to do that? I tried redefining Products to nil, so that any method called would throw an error, it didn't seem to work.
I could find this out if I had a way to take a class and listen to all methods called on it. Is there a way to do that?
Well, you could replace the class with a mock:
Product = mock
From that point on, any method called on Product should generate a failure, e.g. "Mock received unexpected message :find".