charkost / prosopite

:mag: Rails N+1 queries auto-detection with zero false positives / false negatives
Apache License 2.0
1.47k stars 45 forks source link

Failing for a fixture finder #5

Closed drnic closed 3 years ago

drnic commented 3 years ago

I added prosopite, turned on test exceptions, and watched 43 of my tests explode. Cool. Except when I look at the errors, I'm struggling to figure out what is the issue.

One error complains about a rails fixture finder method:

WorkflowAssignableControllerTest#test_0001_searches for people:
Prosopite::NPlusOneQueriesError: N+1 queries detected:
  SELECT "institutions".* FROM "institutions" WHERE "institutions"."id" = $1 LIMIT $2
  SELECT "institutions".* FROM "institutions" WHERE "institutions"."id" = $1 LIMIT $2
  SELECT "institutions".* FROM "institutions" WHERE "institutions"."id" = $1 LIMIT $2
  SELECT "institutions".* FROM "institutions" WHERE "institutions"."id" = $1 LIMIT $2
Call stack:
  /Users/drnic/workspace/prior-study-credit/prior-study-credit/test/models/institution_test.rb:33:in `block in <class:InstitutionTest>'

institution_test.rb:33 is:

class InstitutionTest < ActiveSupport::TestCase
  include ActiveJob::TestHelper

  setup do
    @institution = institutions(:uq) # 33
  end

What is the issue being raised here and what's the fix?

charkost commented 3 years ago

Hello @drnic, thanks for testing out prosopite!

In the README section for tests, the following is mentioned:

# spec/spec_helper.rb

config.before do
  Prosopite.scan
end

config.after do
  Prosopite.finish
end

config.before and config.after in Rspec mean before(:each) and not before(:suite). I should probably make it more explicit in README.

In your minitest case, i guess that you run Prosopite.scan once before all tests and Prosopite.finish once after all tests. You can try to run scan/finish before and after each test. This will probably work.

drnic commented 3 years ago

Ahh, when I saw "And each test can be scanned with:" I thought it was optional.

I'm using minitest and the following looks to make the above test stop failing:

# test/test_helper.rb

module ProsopiteTesting
  def before_setup
    super
    Prosopite.scan
  end

  def after_teardown
    Prosopite.finish
    super
  end
end

class MiniTest::Unit::TestCase
  include ProsopiteTesting
end

Minitest solution based on suggestion in https://stackoverflow.com/questions/16118086/how-to-run-code-before-each-test-case-in-all-tests-in-minitest/16118387