As far as I know, should_receive is applied only to mock objects. What I want is to check, if a certain Class (not object) received a certain message, like:
User.should_receive(:all).once
How do I do that?
UPD. Commonly, writing test for models and controllers we can write User.should_receive(:smth).once. But in my case I'm testing an arbitrary class from the lib folder, and somehow I always receive the following message:
<User( [fields] ) (class)> expected :all with (no args) once, but received it 0 times>
Any ideas on why is that so? A test somehow sees the User class, but can't check if it receives a message. Of course I've ten times checked that the User is actually getting a message.
Easy:
User.should_receive(:all).once
What I want is to check, if a certain Class (not object) received a certain message
A class is an object!
Related
I'm having issues using allow and have_received in my specs
I have a model called Obj that has a belongs_to relationship with a model called Parent. The Parent model has a has_many relationship with Obj.
In the Obj model, I've defined a method called child_method. In the Parent model, I've defined a method called calls_child_method, which iterates through each Obj associated with it and has them call child_method
I'm writing a spec to test this behavior as follows, but it keeps failing:
describe 'parent calls_child_method' do
let(:obj) { Obj.create }
before do
allow(obj).to receive(:child_method)
end
it 'should call child_method' do
obj.parent.calls_child_method
expect(obj).to have_received(:child_method)
end
end
Output:
expected: 1 time with any arguments
received: 0 times with any arguments
However, this seems to pass when I use allow_any_instance_of to do the spy/stubbing:
describe 'parent calls_child_method' do
let(:obj) { Obj.create }
before do
allow(obj).to receive(:child_method)
end
it 'should call child_method' do
expect_any_instance_of(Obj).to receive(:child_method)
obj.parent.calls_child_method
end
end
or if I call the child method directly:
describe 'parent calls_child_method' do
let(:obj) { Obj.create }
before do
allow(obj).to receive(:child_method)
end
it 'should call child_method' do
obj.child_method
expect(obj).to have_received(:child_method)
end
end
In all of this, I've verified that the instance of the Obj that gets created is actually calling child_method by using byebug debugging to see that it is being called.
Can someone help me understand why the spec/spy is behaving like this?
This problem was puzzling me for many years. This is how I understand what is happening.
In your failing case obj is a reference to your newly created Obj.create. By calling expect(obj).to have_received(:child_method) it is expected that EXACT reference obj should receive child_method.
When obj’s parent receives calls_child_method it iterates through each Obj associated with it. Most probably it calls parent.objs which will trigger a new DB call. In your case that will find your obj, but will have a different reference to it. And that different reference will be the one that gets child_method
That’s why technically your object does receive the method call, but through a different reference. As a result your expectation fails:(
expect_any_instance_of(Obj) solves the problem. However it’s usually better to avoid it.
Your last example is successful because your expectation and method call is using the same object/reference.
I have two models, Draft and Pick. Draft creates an array of available Players in an instance variable named 'available_players'. This is done using the 'before_save' callback. The callback runs the instance method 'start' which in turn runs 'set_active_players'. I've tested all of this in my Draft_spec and I have no problems loading players and having them returned in the available_players array. All my draft specs pass.
The problem is that when I try to access the 'available_players' instance variable from Pick.rb, it returns nil. If I call 'draft.start' (the instance method that should run before Draft.rb saves), I can suddenly access the 'available_players' array... it's like the Draft object is not creating the available_players array even though I have the before_save method in place.
Here is the code that fails inside of Pick.rb:
def available_players_returns_nil
#draft_object.available_players
end
Here is the code that works inside of Pick.rb:
def available_players_working
#draft_object.start
#draft_object.available_players
end
I don't want to have to call start every time I call the method because available_players should not need to reload ALL Players. Please help me access available_players!
Links: failing Pick specs, Pick.rb
EDIT:
I should add that #draft_object is found using
#draft_object = Draft.find(self.draft_id)
For a start, this is wrong:
#draft_object = Draft.find(self.draft_id)
You have an association set up, so use it. You can simply use draft within your Pick object to access the Draft it belongs to. No need to assign it to an instance variable called #draft_object.
Same story with player.
Incidentally, your set_available_players method in Draft is just looping through all of the players and adding them to an instance variable. Why are you doing this? Why don't you simply grab the players directly if you need them in Pick? Like this:
#players = Player.all
Also ... I'm somewhat concerned that pretty much all of your tests are commented out. I hope that's not by design?
I want to use Mocks in rspec tests like.
klass.any_instance.should_receive(:save).exactly(2).times.and_return(true)
but I get an error message like:
'The message "save" was received by <#Object> but has already been received by <#Object>'
Temporary I use stub but for accuracy want to use mocks
The documentation of any_instance.should_receive is:
Use any_instance.should_receive to set an expectation that one (and only one)
instance of a class receives a message before the example is completed.
So you have specified that exactly one object should receive the save call two times, and not that 2 objects should receive the save call one time.
If you want to count the calls done by different instances you'll have to be creative like:
save_count = 0
klass.any_instance.stub(:save) { save_count+=1 }
# run test
save_count.should == 2
preface note: I'm just starting to learn Grails, so I'm sure there are many other problems and room for optimization.
I've got two domains, a parent (Collection) and child (Event), in a one-to-many mapping. I'm trying to code an integration test for the deletion of children. Prior to the code in question, I've successfully created a parent and three children. The point where I'm having problems is getting a single child in preparation to delete it. The first line of my sample code is only there because of my rudimentary attempt to troubleshoot.
// lines 95-100 of my EventIntegrationTests.groovy file
// delete a single event
assertEquals("2nd Event", event2.title) // passes
def foundEvent = Event.get(event2.id) // no apparent problems
assertEquals("2nd Event", foundEvent.title) // FAILS (line #98)
foundEvent.delete()
assertFalse Event.exists(foundEvent.id)
The error message I'm getting is:
Cannot get property 'title' on null object
java.lang.NullPointerException: Cannot get property 'title' on null object
at edu.learninggrails.EventIntegrationTests.testEventsDelete(EventIntegrationTests.groovy:98)
What should my next troubleshooting steps be? (Since the first assertEquals passes, event2 is clearly not null, so at this point I have no idea how to troubleshoot the failure of the second assertEquals.)
This is not evident from the code: did you persist event2 by calling save()? Get will try to retrieve it from the persistent storage (the in-memory database for example) and if the event wasn't saved, the retrieved instance will be null.
If you did save it, did the save go through OK? Calling event.save() will return false if there was something wrong while saving the item (like a validation error). Lastly, you might try calling event.save(flush:true) in case the Hibernate session doesn't handle this case as you might expect (I'm not entirely sure about this one, but it can't hurt to try).
Try to print or inspect the event2.id on line 97 and check if you actually have an id, if so check if you actually get an Event object on line 97.
I dont think you saved the parent and its children successfully. after you save, you should make sure that every object that was persisted has a non null id, in your test.
What you are seeing is you created the event2 with a title, but didnt save it. It passes the first assertion because you created it. When you do the get, null is returned because your save failed.
in general for DAO integration tests i do the following
Setup -- create all objects Ill use in the test.
Save -- assert that all ids on saved objects are NOT null.
Clear the hibernate session -- this is important because if you don't do it, objects can be in the session from the previous operations. In your real world scenario, you are probably going to start with a find, i.e. an empty session. In other words, you are not going to start with anything in the session. If you are you need to adjust this rule so that the session in the test, when you start the actual testing part, is the same as the session of the code in the wild
Load the objects on which you want to operate and do what you need to do.
Let's say I have an AddProductToCartTask with a method Execute().
Now, the task is being called from a Controller. In the Execute method , there
is a check that if not met - the action is not performed.
Let's say the message returned would be: "You do not have enough bonus to buy
this product".
I thought about launching an event when the domain validation fails - but that would mean that in the Controller I have to have all kinds of class variables that need checking in the action (to determine if I need to set an error message, or i need to redirect .. etc)
Instead of this I could have a method on the task : GetErrorMessages(). If empty
return the JSON object if not empty return the Message. Or the method could return an enum that would tell if i need to redirect or set a message or return the object ....
I'm not sure which road to take. Any input would be appreciated. How do you bubble up messages from your domain layer ?
Edit: this is mainly in an AJAX context. Even though I'm not sure it matters as it's an action that it's getting called from somewhere .
I might be misunderstanding your request, but it seems to me like you want a central messages functionality, rather than something specific to the task object. If you leave it in your task, then the task must be kept in scope and "alive" until the AJAX request.
I do something similar, though directly from the Controller.
I have a static class called Messages. It has AddMessage(), GetLastMessage(), and GetAllMessages() methods. Each one, when first called, will check the user's session variable and, if nothing is found, creates and saves a Queue<string>() object. The methods are basically just an interface to the Queue. The Queue is nice because it handles push/pop which automatically removed "viewed" messages.
My controller does:
Messages.AddMessage("Product Saved");
You could potentially do:
Messages.AddMessage(task...GetErrorMessages());
Then, from my View, I have an html helper that checks how many error messages there are and, if any, creates a <ul> with each message as a <li>.
You could just as easily have a GetMessages() controller that returns any messages as a JSON object.
James