Reputation: 1474
So I'm writing a test for a method which for performance reasons should achieve what it needs to achieve without using SQL queries. I'm thinking all I need to know is what to stub:
describe SomeModel do
describe 'a_getter_method' do
it 'should not touch the database' do
thing = SomeModel.create
something_inside_rails.should_not_receive(:a_method_querying_the_database)
thing.a_getter_method
end
end
end
EDIT: to provide a more specific example:
class Publication << ActiveRecord::Base
end
class Book << Publication
end
class Magazine << Publication
end
class Student << ActiveRecord::Base
has_many :publications
def publications_of_type(type)
#this is the method I am trying to test.
#The test should show that when I do the following, the database is queried.
self.publications.find_all_by_type(type)
end
end
describe Student do
describe "publications_of_type" do
it 'should not touch the database' do
Student.create()
student = Student.first(:include => :publications)
#the publications relationship is already loaded, so no need to touch the DB
lambda {
student.publications_of_type(:magazine)
}.should_not touch_the_database
end
end
end
So the test should fail in this example, because the rails 'find_all_by' method relies on SQL.
Upvotes: 4
Views: 5363
Reputation: 232
Call
ActiveRecord::Base.connection.disconnect!
before calling the method, and check if there was no error raised.
Upvotes: -1
Reputation: 36
I don't have enough points yet to comment, but following up on the answer left by @histocrat, and the comment left by @will-tomlins. If you stub ActiveRecord::Base.connection
in place of the SomeModel.connection
you will avoid getting the 'stack level too deep' message, and instead get an error from the matcher itself.
Upvotes: 0
Reputation: 121
I know this question is super old now, but I stumbled across it trying to do the same thing. After looking around some more I've found there's a great and simple gem for this.
https://github.com/brigade/db-query-matchers
It adds an rspec matcher that takes a block so you can just use:
expect { subject.make_no_queries }.to_not make_database_queries
The configuration is super simple too, and it means you can have some calls that do make queries mixed in with a subset of calls that do connect to the database.
Upvotes: 3
Reputation: 50057
SomeModel.create
creates the an instance of SomeModel
and saves it to the database, and returns the created object.
Do you want to make sure that any getter method does not acces the database? In rails only retrieving associations will hit the database, and only the first time they are called.
If you have a specific implementation of a getter method, which you "suspect" would hit the database, I would assume it would be easy to test, or are you protecting against future implementations?
Maybe the easiest way would be to do SomeModel.build
, and then perform your test. The build
creates an instance, without saving it to the database. If the getter works, it sure didn't hit the database (since nothing should be there ---depending on your code --a bit hard to say without any clue what getter you are actually testing).
If you are testing a specific getter method, and want more relevant answer, please provide some code.
Upvotes: 0