Top AI Repos — open-source AI, indexed and scored
Top AI Repos tracks AI repositories on GitHub and answers two different questions about each one: is it moving right now, and would you bet a product on it.
Top AI Repos tracks AI repositories on GitHub and answers two different questions about each one: is it moving right now, and would you bet a product on it.
RSpec and Minitest matchers to prevent N+1 queries problem
| Date | Stars |
|---|---|
| 2026-07-24 | 580 |
| 2026-07-25 | 580 |
| 2026-07-28 | 580 |
| 2026-07-30 | 580 |
| 2026-08-06 | 580 |
Today
— stars today
This week
— stars this week
This month
— stars this month
Momentum
0.0
growth rate 0.00%/day
[](https://rubygems.org/gems/n_plus_one_control)

# N + 1 Control
RSpec and Minitest matchers to prevent the N+1 queries problem.
<img src="https://s3.amazonaws.com/anycable/n_plus_one_control.png" alt="Example output" width="553px">
### Why yet another gem to assert DB queries?
Unlike other libraries (such as [db-query-matchers](https://github.com/brigade/db-query-matchers), [rspec-sqlimit](https://github.com/nepalez/rspec-sqlimit), etc), with `n_plus_one_control` you don't have to specify exact expectations to control your code behaviour (e.g. `expect { subject }.to query(2).times`).
Such expectations are rather hard to maintain, 'cause there is a big chance of adding more queries, not related to the system under test.
NPlusOneControl works differently. It evaluates the code under consideration several times with different scale factors to make sure that the number of DB queries behaves as expected (i.e. O(1) instead of O(N)).
So, it's for _performance_ testing and not _feature_ testing.
> Read also ["Squash N+1 queries early with n_plus_one_control test matchers for Ruby and Rails"](https://evilmartians.com/chronicles/squash-n-plus-one-queries-early-with-n-plus-one-control-test-matchers-for-ruby-and-rails).
### Why not just use [`bullet`](https://github.com/flyerhzm/bullet)?
Of course, it's possible to use Bullet in tests (see more [here](https://evilmartians.com/chronicles/fighting-the-hydra-of-n-plus-one-queries)), but it's not a _silver bullet_: there can be both false positives and true negatives.
This gem was born after I've found myself not able to verify with a test yet another N+1 problem.
<br/>
<img src="https://cdn.evilmartians.com/badges/logo-no-label.svg" alt="Evil Martians logo" width="22" height="16" /> <b>N+1 Control</b> is built by <b><a href="https://evilmartians.com/">Evil Martians</a></b>, an American design and engineering consultancy for <b>developer tools, AI, and cybersecurity startups</b>.
## Installation
Add this line to your application's Gemfile:
```ruby
group :test do
gem "n_plus_one_control"
end
```
And then execute:
$ bundle
## Usage
### RSpec
First, add NPlusOneControl to your `spec_helper.rb`:
```ruby
# spec_helper.rb
require "n_plus_one_control/rspec"
```
Then:
```ruby
# Wrap example into a context with :n_plus_one tag
context "N+1", :n_plus_one do
# Define `populate` callbacks which is responsible for data
# generation (and whatever else).
#
# It accepts one argument – the scale factor (read below)
populate { |n| create_list(:post, n) }
specify do
expect { get :index }.to perform_constant_number_of_queries
end
end
```
**NOTE:** do not use memoized values within the expectation block!
```ruby
# BAD – won't work!
subject { get :index }
specify do
expect { subject }.to perform_constant_number_of_queries
end
# GOOD
specify do
expect { get :index }.to perform_constant_number_of_queries
end
# BAD — the `page` record would be removed from the database
# but still present in RSpec (due to `let`'s memoization)
let(:page) { create(:page) }
populate { |n| create_list(:comment, n, page: page) }
specify do
expect { get :show, params: {id: page.id} }.to perform_constant_number_of_queries
end
# GOOD
# Ensure the record is created before `populate`
let!(:page) { create(:page) }
populate { |n| create_list(:comment, n, page: page) }
# ...
```
Availables modifiers:
```ruby
# You can specify the RegExp to filter queries.
# By default, it only considers SELECT queries.
expect { get :index }.to perform_constant_number_of_queries.matching(/INSERT/)
# You can also provide custom scale factors
expect { get :index }.to perform_constant_number_of_queries.with_scale_factors(10, 100)
# You can specify the exact number of expected queries
expect { get :index }.to perform_constant_number_of_queries.exactly(1)
```Excerpt of 11,828 characters
Read on GitHubVladimir Dementyev · @evilmartians · United States
52
11
8
4
3
2
2
1
1
1
1
1
1
1
1
Peter Goldstein · Hearst
1
1
Would you bet a product on this? Bounded 0–100 and slow moving.
matched fp:68cefb942494577d, topic:testing