A proper way to test that database is not accessed?

Hello,

Previously I’ve had a helper assert_no_database like this:

def assert_no_database

old_con = ActiveRecord::Base.remove_connection

begin

yield

ensure

ActiveRecord::Base.establish_connection old_con

end

end

But it doesn’t work in Rails 3.1.1 anymore (due to the following change: https://github.com/rails/rails/issues/2820)

Any suggestion for a proper way to check that a block of code doesn’t access database?

Thanks,

KIR

How about:

  ActiveRecord::Base.establish_connection Rails.env

ActiveRecord::Base.establish_connection Rails.env

I don’t quite understand what do you mean here?

My problem is that code like the following results in ConnectionNotEstablished exception (though it worked in 3.1):

model = Task.first
old_con = ActiveRecord::Base.remove_connection
model.any_attr_name # check no access to DB
ActiveRecord::Base.establish_connection old_con

I know what your problem is. If because of changes to Rails reconnecting to the db by using the old connection doesn’t work, then I suggested that you give up on using the old connection and just instruct AR to connect as if the application was just booting up. Have you tried what I suggested at all? Are you having the same problem?

def without_database_connection

ActiveRecord::Base.remove_connection

begin

  yield

ensure

  ActiveRecord::Base.establish_connection Rails.env

end

end

I know what your problem is. If because of changes to Rails reconnecting to the db by using the old connection doesn’t work, then I suggested that you give up on using the old connection and just instruct AR to connect as if the application was just booting up. Have you tried what I suggested at all? Are you having the same problem?

def without_database_connection

ActiveRecord::Base.remove_connection
begin
  yield
ensure
  ActiveRecord::Base.establish_connection Rails.env
end

end

Thanks Mislav, I tried your suggestion, but it doesn’t work.

My actual problem is not about restoring the connection (but thanks for the tip, I may need it eventually).

It is about the fact that I always get exception when I’m trying to access model attributes when connection was removed with remove_connection (i.e. I get exception in the yield part).

BTW, have you tried your helper on Rails 3.1.1?

Thanks,

KIR

I haven’t tried my code, I just pulled it out of the air. Sorry that I misunderstood your problem – I thought it was about reconnecting.

I have the feeling that others also didn’t get what you were saying; people who got notified about your comment on the issue tracker probably thought that you have a problem in your custom helper.

The most important thing right now to establish whether this is a real bug or not. The behavior which you relied on before the offending change might not have been intentional. It’s possible that you might be testing wrong things in your application.

You should describe what are you doing inside the no connection block. (You mentioned using attribute accessors, but in order to generate these accessors, AR must have an open connection so it can fetch information about table columns.) Describe shortly what you were expecting to get and how the new behavior surprises you and breaks your tests.

You should describe what are you doing inside the no connection block. (You mentioned using attribute accessors, but in order to generate these accessors, AR must have an open connection so it can fetch information about table columns.) Describe shortly what you were expecting to get and how the new behavior surprises you and breaks your tests.

Basically, I have a test that I don’t have N+1 problem when collecting data.

I do something like this:

in the production, this may generate hundreds of items (which have own associations)

sub_model_items = model.preload_subitems

assert_no_database {

json = sub_model_items.build_json

}

What I’m trying to test - that my code doesn’t perform SQL operations when building json, i.e. all data should be preloaded.

Thanks,

KIR

That’s a perfectly valid thing to test. Looks like it might be a regression. I suggest that you update the issue (where you commented on) with this information, including your own code related to this and provide a stack trace pasted into a Gist.

Until you have a solution for this problem, I suggest testing this another way. In will_paginate, I subscribe to all SQL queries performed and then I check them in tests to see whether there have been too many executed during a particular test.

What I’m trying to test - that my code doesn’t perform SQL operations when building json, i.e. all data should be preloaded.

That’s a perfectly valid thing to test. Looks like it might be a regression. I suggest that you update the issue (where you commented on) with this information, including your own code related to this and provide a stack trace pasted into a Gist.

Until you have a solution for this problem, I suggest testing this another way. In will_paginate, I subscribe to all SQL queries performed and then I check them in tests to see whether there have been too many executed during a particular test.

Thanks a lot for the hint, will investigate it.

May be, I’ll be able to rewrite my assert_no_database assertion using its approach.

All the best,

KIR

There's assert_queries/assert_no_queries in the test case support code, which sound quite similar to what you want. But it needs a subscriber implementation (such as Mislav was talking about for will_paginate), which you need to feed into the global variable that the assertions check.

Rails has a subscriber implementation for its own tests, but it isn't exposed. IMHO it would be great it did, so we could just instantiate that in app test code without having to copy it in (it's somewhat version-specific).

Have a look at activerecord/test/cases/helper.rb to see how it works. The assertions that use it are defined in activerecord/lib/active_record/test_case.rb, so they are exposed, which doesn't make much sense at the moment.

Will, Mislav, thanks for all your help!

I’ve used subscriber to implement my assert_no_database helper. When asserted block of code performs any SQL requests, these requests are included into test output: https://gist.github.com/1305807

Thanks again!

KIR