Skip to content

Instantly share code, notes, and snippets.

@hakunin
Last active November 16, 2016 11:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hakunin/329897cc0d616346c088175301ddaae1 to your computer and use it in GitHub Desktop.
Save hakunin/329897cc0d616346c088175301ddaae1 to your computer and use it in GitHub Desktop.
Prevent different records with matching IDs from falsely passing tests
# put this inside spec/support/random_ids.rb
# NOTE: this works, but will break tests whee something like Article.last is used
# a more clever approach is used in 02 below
# Some tests may pass when they should have failed
# due to Rails using sequential ids. This allows us
# to fix that by having random ids.
class ActiveRecord::Base
before_create :generate_random_id
private
def generate_random_id
return if self.id
begin
# assuming 4 byte postgresql range
self.id ||= SecureRandom.random_number(2147483647)
end while self.class.where(id: self.id).exists?
end
end
# this is the ideal approach, if you're using PostgreSQL
# namespacing each sequence so they don't overlap
RSpec.configure do |config|
config.before :suite do
# assuming each record will have maximum of 99 999 records created,
# in a single test suite, which should be more than enough
namespace_size = 100_000
# select sequences so we can set their start
sequences = ActiveRecord::Base.connection.execute("SELECT c.relname FROM pg_class c WHERE c.relkind = 'S'")
sequences.each_with_index { |result, i|
sequence = result['relname']
start = namespace_size * (i + 1)
# start each sequence namespaced
ActiveRecord::Base.connection.execute("SELECT setval('#{sequence}', #{start})")
}
end
end
@romansklenar
Copy link

Nice one @hakunin ! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment