RSpec stubbing a complex Rails result to test one nested field - ruby-on-rails

I'm using RSpec's stubbing functionality to stub a where() call on an object:
allow(ActiveRecordObject).to_receive(:where).and_return(result)
This works great when the expected result is simple, such as an instance of the ActiveRecordObject with a field set to a certain value.
However, the result I want to test is more complex. I'm intending to test a value set on another ActiveRecordObject that is nested three deep through Rails hasMany functionality and this is more tricky. For example, I'd like ...
expect(result[:child_object][:test_target][:field]).to eq(value)
... to work as a test after the function that I'm testing is called.
The way I've attempted and so far failed to achieve this is by copying the structure of the object so the result is a considerably more complex.
What I'd like to do is stub the actual call (or value, if a call isn't really made) to test_target so when the call is made a much more simple stub is hit. This seems to me to be better as it creates less brittle, easier to understand code.
I've also tried stubbing a where() method on the class TestTarget.
What is the correct way to configure values in linked ActiveRecord objects in RSpec so that when the parent object is called the resulting structure contains a value hard-coded for test.
Also, is this possible without using Factory Girl (tech leads at work have decided that we want to move away from using FactoryGirl)

Related

OCMClassMock and OCMStrictClassMock

I am new in OCMock 3, I see there are two methods:
OCMClassMock(cls): creates a new nice class mock object
OCMStrictClassMock(cls): creates a class mock object
I read the document, but I feel still confused & have two questions:
What exactly the difference between OCMClassMock(cls) and OCMStrictClassMock(cls) ?
When should I use OCMClassMock(cls) and when should I use OCMStrictClassMock(cls)?
====UPDATE====
Can I understand as OCMClassMock(cls) is partial mock that the real implementation still run when call method on it and OCMStrictClassMock(cls) is a full mock like a skeleton without real implementation?
Can I understand as OCMClassMock(cls) is partial mock that the real
implementation still run when call method on it
This describes OCMPartialMock.
OCMStrictClassMock(cls) is a full mock like a skeleton without real
implementation?
This is an accurate general description of OCMClassMock.
From the reference you linked:
[OCMStrictClassMock] Creates a mock object in strict mode. By
default mocks are nice, they return nil (or the correct default value
for the return type) for whatever method is called. In contrast,
strict mocks raise an exception when they receive a method that was
not explicitly expected.
So as you said, OCMClassMock is like a skeleton of an instance where you only stub the methods that you need to use. The difference between OCMClassMock and OCMStrictClassMock is that the former will simply return nil for a method that you haven't explicitly stubbed, whereas the latter will throw an exception if you call a method on it that you haven't explicitly stubbed.

How can I get access to the class instance that is rendering my view in a test?

I'm trying to test a rake task which scrapes my site and pushes the content to an elasticsearch server; the task works fine. However the test is failing because in one view I randomly pick some values like this:
[:breast,:ovarian][rand(2)]
(rand * 4)-2
rand(Date.new(2006)..Time.now.to_date)
Which means I need to stub rand. In order to stub rand I need access to the class-instance that is calling it, which in this case is whatever class is rendering my view. Calling puts self.class Just returns Class and an id, so how can I get ahold of the instance in order to stub it?
I could pass these values into the view from the controller as instance variables, if getting ahold of the controller would be easier.
long story short: it would be better to extract the offending logic and place it in a helper. This way you will be able to stub it easily, and even unit-test it if needed. Moreover this improves the overall quality of your code (no logic should belong to the view).
also, rand is a method from Kernel, so it is already "stubable"

call arbitrary chained methods on wrapper class

I'm creating a wrapper class for an API because my application will need to call it with different credentials at different times. I started off passing the wrapper a method and arguments and then doing (basically) this when calling it
call
set_credentials
TheAPI::Thing.send(method, args)
ensure
reset_credentials_to_default
end
HOWEVER, I realized that a challenge here is if I need to chain methods; this way I can only call one at a time; so for example I wouldn't be able to to TheAPI::Thing.find(id).delete. (At least, not without re-calling the credentials setter, which is undesirable since I have to fetch a token).
Is there a way using ruby to collect the methods/args being chained onto an object? Or would I simply have to pass in some ugly ordered set of things?
EDIT: Surely activerecord's query builder does something like this, collecting the chained methods before returning, and then after they're all collected, ensuring that as a final step the query is built, called, and returned?
the way to do this is to define a proxy object and to pass that around instead of the actual thing.
In the object itself, hold a reference to the Thing and override method_missing: http://ruby-doc.org/core-2.1.0/BasicObject.html#method-i-method_missing
In the method missing do the thing you are doing today. In a nutshell this is what ActiveRecord is doing.
As far as chaining things, I don't believe it would be a problem as methods that can be chained usually return references to self. When you call the 2nd method in the chain, you actually have done the work for the first one and have an object that has the 2nd method in the chain. The only trick you need to pay attention to is that you want to return a reference to the proxy class that encapsulates the thing instead of the actual return of the thing if you want the chaining to succeed.
Give it a shot and ping me if you run into trouble and I can spin up a fully working example.

Why is mocking with DI better than mocking objects in objective-c?

this blog article says that:
While there are sometimes sensible ways to mock out objects without DI
(typically by mocking out class methods, as seen in the OCMock example
above), it’s often flat out not possible. Even when it is possible,
the complexity of the test setup might outweigh the benefits. If
you’re using dependency injection consistently, you’ll find writing
tests using stubs and mocks will be much easier.
but it doesn't explain why. What are possible scenarios where DI (injecting an id object conforming to protocol) will serve better for mocking in Objective-C, than simple OCMockito:
[given([mockArray objectAtIndex:0]) willReturn:#"first"];
[verifyCount(mockArray, times(1)) objectAtIndex:];
?
I've noticed that it is easier to create a separate class for test target when the original class do some async stuff.
Let assume you write a test for UIViewController which has a LoginSystem dependency which uses AFNetworking to do a request to the API. LoginSystem takes a block argument as a callback. (UIViewController->LoginSystem->AFNetworking).
If you make a mock of LoginSystem probably you will end with problems how to fire a callback block to test your UIViewController behaviour on success/failure. When I tried that I ended with MKTArgumentCaptor to retrieve a block argument and then I had to invoke it inside a test file.
On the other hand, if you create a separate class for LoginSystem (let call it LoginSystemStub which extends from LoginSystem) you are able to "mock" a behaviour in 3 lines of code and outside the test file. We should also keep our test file clean and readable.
Another case is that verify() doesn't work with checking asynchronous behaviour. It is much more easier to call expect(smth2).will.equal(smth)
EDIT:
Pointers to NSError (NSError**) also don't work well with verify() and it's better to create a stub :D
Imagine you are trying to test a more complex behavior of an object interacting with one of its child objects. To make certain that the parent object is operating correctly, you have to mock all the methods of the child object and even potentially track its changing state.
But if you do that, you just wrote an entirely new object in a confusing and convoluted way. It would have been simpler to write an entirely new object and tell the parent to use that.
With DI you inject your model at runtime, it's not bound in your classes but only in the configuration.
When you want to mock you just create a mock model and inject that instead of your real data. Besides the model, you changed your implementation in a single line.
See here for a hands on example or here for the idea behind it.
Disclaimer: Of course you can mock other stuff than the model, but that's probably the most common use-case.
The answer is: It's not better. It's only better if you need some super custom behavior.
The best thing about it is that you don't have to create an interface/protocol for every class you inject and you can limit to DI the modules you really need to inject making your code cleaner and more YAGNI.
It applies to any dynamic language, or language with reflection. Creating so much clutter just for the sake of Unit-Tests struck me as a bad idea.

different behavior of method when immediately accessing the results

I have a class method Juxtaposition.generate_for(position) on a class that I am calling from a spec. The method sets up a map reduce and calls it map_reduce(map, reduce).out(merge: "juxtapositions")
The position variable is defined in a let prior to the it block.
When executing if I simply call the function above (which is really only calling a map reduce on data related to the position) then tests like below fail:
Juxtaposition.count.should eq 1
Juxtaposition.first.value.should eq values
However, if I call
Juxtaposition.generate_for(positions).first["value"].should eq values
prior to the two tests then they both pass. The above two tests also pass when I use pry and call the generate_for method from there.
Is there some strange behavior of map reduce in mongoid that I should be aware of? Or, is there some way to force the results into my later queries.
Solution was simple enough. I just need to make sure to call find on the call to map reduce.
More specifically:
map_reduce(map, reduce).out(merge: "juxtapositions").first
or
map_reduce(map, reduce).out(merge: "juxtapositions").to_a
Without to_a or first the actual map reduce doesn't execute it seems, even if it's meant to be stored in another collection.

Resources