Testing Database Queries Made in RSpec
Recently, Joe and I have been doing some performance work on causes.com to speed up the time it takes to generate a page on the server. Most of that work meant reducing the number of database queries we make. Take the profile page for example. On that page, we list the most important campaigns you’ve participated in. Before we started optimizing it, we were making more than 10 queries per campaign listed. We added some pre-loading and caching and managed to take all those database queries down by 90%. That in turn brought the time it took to generate this page down from about a second to 200 milliseconds.
Testing the avoidance of database queries
In order to verify that the work we did had the effect we intended, and to guard us against future regressions, we built a tool to use in our unit tests that counts the number of database queries made by running a particular piece of code. Here’s an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
The interesting part here is the make_database_queries
RSpec matcher. It
hooks into ActiveRecord and detects all database queries made during the
execution of the block. If you don’t expect queries, but some are made, the
spec will fail with a list of the queries made. This makes debugging much
simpler, since you can usually narrow down the query to a missing includes
.
Introducing the db-query-matchers
gem
We bundled the make_database_queries
matcher into a
reusable gem. Next time you add a caching layer or fix an
N+1 query, make sure to add the performance improvement to your test suite!
Check out the project on Github: https://github.com/causes/db-query-matchers