Stubbing with FactoryGirl, MiniTest, and Rails 4 - ruby-on-rails

I am a big fan of FactoryGirl, but have never understood the ".build_stubbed" method and would like to incorporate stubbing/mocking into my TDD. Can someone help me with the basics of what kind of stubbing I can do with FactoryGirl? Should I start using Mocha or another similar GEM to handle the mocking/stubbing or is any of this included in the Rails 4 default MiniTest?

The factory girl command build_stubbed means that the object is created (and also all its associated objects) but no objects are inserted into the database. You should use this if you want faster tests and do not need to have the objects in the database.
This means that the command does not have to do much with stubbing or mocking.
I myself have only experience with Mocha and can say that it very easy to use it for stubbing and mocking.
For stubbing out a command (e.g. of the object Person)
person = Person.new
person.stubs(:name).returns('Robert')
The obove example creates an instance of the person and stubbes out the method name to always return 'Robert'.
For mocking out the same command
person = Person.new
person.expects(:name).returns('Robert')
The above does the same as stubbing out the method. With the only difference that now the test fails if the method name is not called exactly once.

Related

Ruby on Rails - Understanding Database Dependencies in Test

I've got some model code that calls to the database with a simple find():
#thing = Thing.find(id)
I have data seeded in the database for the test environment. If I open the console in test (rails c -e test), I can run Thing.find(1) and get a result fine, however when I run a test that calls the method shown above, it reports that it cannot find a record with the id of 1.
I assume I am misunderstanding the relationship between test seed data and the tests being run against that database. Why do I see seed sin the test DB but the test doesn't?
A more conventional way of doing this would be to create fixtures (or factories if using FactoryBot) and call these factories in your test setup. As previous answers have said, hardcoding test ID's will likely return RecordNotFound due to auto-incrementing.

Using Rails test fixture helpers in Cucumber

I'd like to be able to use Rails' test fixture helpers in Cucumber, but the information provided on the Cucumber wiki seems... out of date at best: https://github.com/cucumber/cucumber/wiki/Fixtures (heading: Fixture Helper Methods)
Google has been less than helpful.
Is there a good way to do this?
Update: Tried using ActiveRecord::TestFixtures to no avail it seems like this is the class to do the job, but can't get it mixed into the World correctly
One of the reasons there's so little information on fixtures is that most rails developers are now all using Factory Girl to generate test data.
Factory Girl provides you mush more control over both the data that's generated (and when it's created), but it also allows you a lot more control of the associated model classes you inevitably will need.
After an hour of brain cramming, I was able to make it work.
Replace
fix = Fixtures.cached_fixtures(ActiveRecord::Base.connection, table_name)[fixture_symbol.to_s]
with
fix = Fixtures.cached_fixtures(ActiveRecord::Base.connection, table_name).first.fixtures[fixture_symbol.to_s]
I have already updated the wiki at https://github.com/cucumber/cucumber/wiki/Fixtures

Testing Rails model validations

There's many examples of testing RoR model validations. Even keeping the test being DRY across multiple models. But isn't it testing Rails which is already tested?
#user = User.make
#user.name = nil
#user.should_not be_valid
Isn't it testing if Rails validations work?
Isn't it testing if Rails validations work?
The point is that it tests that your model validates the presence of name. The fact that it also in effect tests that the Rails validation works, that Rspec works, that Ruby works, that your OS works, and that the rules of physics haven't suddenly changed, is beside the point.
The point is that you test that your model is using the validation. I agree with you, though, that your example tests the validation itself, and the test is also somewhat ambiguous.
If you are using the shoulda gem, you can simply use should validate_presence_of(:name).
Think of a method in your program where you have called update_attribute (update_attribute skips validation). Calling that method leaves the object in an invalid state, however the database still gets updated. Using valid?/invalid? can help you catch such cases.

How can I optionally mock geocoder?

I'd like to be able to mock the results of the geocoder gem in some of my tests.
I use RSpec and Cucumber. In cucumber I'd like to default to mocking the Geocoder results, but be able to turn it back on again by adding a tag. That would be perfect! Something similar for RSpec would be good too. It would speed up my tests enormously.
I know there are some gems out there for doing similar things, e.g. sunspot_test for sunspot. Is there anything similar for geocoder?
You can use mocha to stub and mock calls. If you do something like (and I'm just making this up because I don't know the GeoCoder syntax):
GeoCoder.get_data(x, y)
And that's something you want to stub out and force to return something else, mocha allows you to do:
GeoCoder.stubs(:get_data).with(x, y).returns(my_own_variable)
And that will make any call to GeoCode.get_data, when passed in x and y, to return your custom variable. However, this stub will last for all subsequent calls during your test, so you can unstub it by calling:
GeoCoder.unstub(:get_data)
And that completely restores that method to normal.
In terms of Rspec, in a teardown block you can unstub. In terms of Cucumber, you can add a tag like #stubs_geocoder before scenarios, and within features/support/env.rb you can add this:
Before('#stubs_geocoder') do
# add your stub calls
end
After('#stubs_geocoder') do
# unstub
end
Im using vcr gem for remote services, check it out! It can be very useful in your situation. github.com/myronmarston/vcr

run database with rspec-rails

I am trying to test a controller with RSpec but am having a problem because a function in the controller requires a database.
the line of code in the controller looks something like:
#myallresources = Myrsources.all
where Myresources just inherits from ActiveRecord::Base
however, because there is no database, there is nothing to load and #myallresources is just an empty array, causing the test to fail. Is there a way to connect to a database while running the rspec?
I am very new to RSpec and rails so any help would be very appreciated. Thanks.
You shouldn't use a database connection in your controller specs.
Check the section about database isolation on this page http://rspec.info/rails/writing/controllers.html
Basically you have to mock or stub your ActiveRecord models, as those should be tested separately in the models specs. Here's a simple example using mock_model:
before do
mocks = (1..3).map { mock_model(MyResource) }
MyResource.should_receive(:all).and_return(mocks)
end
Put this inside the same block where reside the describe definition testing for the actions that use MyResource.all.
You can find good explanation of mocks and stubs in following links:
http://relishapp.com/rspec/rspec-rails/v/2-5/docs/mocks/mock-model
http://relishapp.com/rspec/rspec-rails/v/2-5/docs/mocks/stub-model

Resources