Skip to content

Commit

Permalink
Merge pull request #50281 from p8/activerecord/assert-queries
Browse files Browse the repository at this point in the history
Expose `assert_queries` and `assert_no_queries` assertions
  • Loading branch information
byroot committed Dec 11, 2023
2 parents 109bb44 + 8392c54 commit 3881518
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 48 deletions.
19 changes: 2 additions & 17 deletions actiontext/test/test_helper.rb
Expand Up @@ -6,6 +6,7 @@
ENV["RAILS_ENV"] = "test"

require_relative "../test/dummy/config/environment"
require "active_record/testing/query_assertions"
ActiveRecord::Migrator.migrations_paths = [File.expand_path("../test/dummy/db/migrate", __dir__)]
require "rails/test_help"

Expand All @@ -26,23 +27,7 @@
class ActiveSupport::TestCase
module QueryHelpers
include ActiveJob::TestHelper

def assert_queries(expected_count, &block)
ActiveRecord::Base.connection.materialize_transactions

queries = []
ActiveSupport::Notifications.subscribe("sql.active_record") do |*, payload|
queries << payload[:sql] unless %w[ SCHEMA TRANSACTION ].include?(payload[:name])
end

result = _assert_nothing_raised_or_warn("assert_queries", &block)
assert_equal expected_count, queries.size, "#{queries.size} instead of #{expected_count} queries were executed. #{queries.inspect}"
result
end

def assert_no_queries(&block)
assert_queries(0, &block)
end
include ActiveRecord::Assertions::QueryAssertions
end

private
Expand Down
15 changes: 2 additions & 13 deletions actionview/test/activerecord/relation_cache_test.rb
@@ -1,9 +1,11 @@
# frozen_string_literal: true

require "active_record_unit"
require "active_record/testing/query_assertions"

class RelationCacheTest < ActionView::TestCase
tests ActionView::Helpers::CacheHelper
include ActiveRecord::Assertions::QueryAssertions

def setup
super
Expand All @@ -24,17 +26,4 @@ def test_cache_relation_other
end

def view_cache_dependencies; []; end

def assert_queries(num, &block)
ActiveRecord::Base.connection.materialize_transactions
count = 0

ActiveSupport::Notifications.subscribe("sql.active_record") do |_name, _start, _finish, _id, payload|
count += 1 unless ["SCHEMA", "TRANSACTION"].include? payload[:name]
end

result = _assert_nothing_raised_or_warn("assert_queries", &block)
assert_equal num, count, "#{count} instead of #{num} queries were executed."
result
end
end
16 changes: 16 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,19 @@
* Make `assert_queries` and `assert_no_queries` assertions public.

To assert the expected number of queries are made, Rails internally uses
`assert_queries` and `assert_no_queries`. These assertions can be now
be used in applications as well.

```ruby
class ArticleTest < ActiveSupport::TestCase
test "queries are made" do
assert_queries(1) { Article.first }
end
end
```

*Petrik de Heus*

* Fix `has_secure_token` calls the setter method on initialize.

*Abeid Ahmed*
Expand Down
24 changes: 24 additions & 0 deletions activerecord/lib/active_record/testing/query_assertions.rb
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module ActiveRecord
module Assertions
module QueryAssertions
def assert_queries(expected_count, matcher: nil, &block)
ActiveRecord::Base.connection.materialize_transactions

queries = []
ActiveSupport::Notifications.subscribe("sql.active_record") do |*, payload|
queries << payload[:sql] if %w[ SCHEMA TRANSACTION ].exclude?(payload[:name]) && (matcher.nil? || payload[:sql].match(matcher))
end

result = _assert_nothing_raised_or_warn("assert_queries", &block)
assert_equal expected_count, queries.size, "#{queries.size} instead of #{expected_count} queries were executed. Queries: #{queries.join("\n\n")}"
result
end

def assert_no_queries(&block)
assert_queries(0, &block)
end
end
end
end
36 changes: 36 additions & 0 deletions activerecord/test/cases/assertions/query_assertions_test.rb
@@ -0,0 +1,36 @@
# frozen_string_literal: true

require "cases/helper"
require "models/post"
require "active_record/testing/query_assertions"

module ActiveRecord
module Assertions
class QueryAssertionsTest < ActiveSupport::TestCase
include QueryAssertions

def test_assert_queries
assert_queries(1) { Post.first }

error = assert_raises(Minitest::Assertion) {
assert_queries(2) { Post.first }
}
assert_match(/1 instead of 2 queries/, error.message)

error = assert_raises(Minitest::Assertion) {
assert_queries(0) { Post.first }
}
assert_match(/1 instead of 0 queries/, error.message)
end
end

def test_assert_no_queries
assert_no_queries { Post.none }

error = assert_raises(Minitest::Assertion) {
assert_no_queries { Post.first }
}
assert_match(/1 .* instead of 2/, error.message)
end
end
end
20 changes: 3 additions & 17 deletions activestorage/test/test_helper.rb
Expand Up @@ -12,6 +12,8 @@
require "active_support/testing/autorun"
require "image_processing/mini_magick"

require "active_record/testing/query_assertions"

require "active_job"
ActiveJob::Base.queue_adapter = :test
ActiveJob::Base.logger = ActiveSupport::Logger.new(nil)
Expand All @@ -24,6 +26,7 @@ class ActiveSupport::TestCase
self.file_fixture_path = ActiveStorage::FixtureSet.file_fixture_path

include ActiveRecord::TestFixtures
include ActiveRecord::Assertions::QueryAssertions

self.fixture_paths = [File.expand_path("fixtures", __dir__)]

Expand All @@ -35,23 +38,6 @@ class ActiveSupport::TestCase
ActiveStorage::Current.reset
end

def assert_queries(expected_count, matcher: nil, &block)
ActiveRecord::Base.connection.materialize_transactions

queries = []
ActiveSupport::Notifications.subscribe("sql.active_record") do |*, payload|
queries << payload[:sql] if %w[ SCHEMA TRANSACTION ].exclude?(payload[:name]) && (matcher.nil? || payload[:sql].match(matcher))
end

result = _assert_nothing_raised_or_warn("assert_queries", &block)
assert_equal expected_count, queries.size, "#{queries.size} instead of #{expected_count} queries were executed. Queries: #{queries.join("\n\n")}"
result
end

def assert_no_queries(&block)
assert_queries(0, &block)
end

private
def create_blob(key: nil, data: "Hello world!", filename: "hello.txt", content_type: "text/plain", identify: true, service_name: nil, record: nil)
ActiveStorage::Blob.create_and_upload! key: key, io: StringIO.new(data), filename: filename, content_type: content_type, identify: identify, service_name: service_name, record: record
Expand Down
3 changes: 2 additions & 1 deletion railties/lib/rails/test_help.rb
Expand Up @@ -11,15 +11,16 @@
require "action_controller/test_case"
require "action_dispatch/testing/integration"
require "rails/generators/test_case"

require "active_support/testing/autorun"

require "rails/testing/maintain_test_schema"

if defined?(ActiveRecord::Base)
require "active_record/testing/query_assertions"
ActiveSupport.on_load(:active_support_test_case) do
include ActiveRecord::TestDatabases
include ActiveRecord::TestFixtures
include ActiveRecord::Assertions::QueryAssertions

self.fixture_paths << "#{Rails.root}/test/fixtures/"
self.file_fixture_path = "#{Rails.root}/test/fixtures/files"
Expand Down

0 comments on commit 3881518

Please sign in to comment.