Skip to content

Instantly share code, notes, and snippets.

@tenderlove
Created Nov 7, 2014
Embed
What would you like to do?
require 'active_record'
require 'logger'
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
ActiveRecord::Base.connection.instance_eval do
create_table(:parents)
create_table(:children) do |t|
t.references :parent
end
end
class Parent < ActiveRecord::Base
has_many :children
end
class Child < ActiveRecord::Base
belongs_to :parent
inc = 0
default_scope -> {
inc += 1
where("id = :inc", :inc => inc)
}
end
parent = Parent.create
10.times do
parent.children.create
end
ActiveRecord::Base.logger = Logger.new $stderr
parent.reload
parent.children.to_a
parent.children.reset
parent.children.to_a # produces the wrong query
parent.children.reset
parent.children.to_a # also produces the wrong query
__END__
This is a script proviede to reproduce a bug. It's easy to run, and easy to
reproduce the bug. The *hard* part is finding a model in
activerecord/test/cases/models where we can set up a relationship that looks
exactly like this one. It takes time to sift through existing models to find
one that looks "close enough" or can be easily modified to fit the bug.
This specific case is even harder because it requires a default_scope, which
will globally modify the behavior of the model.
In short, the problem isn't with the test cases we get, the problem is
integrating them with our test suite.
@myronmarston
Copy link

myronmarston commented Nov 7, 2014

Have you considered moving away from having global activerecord/test/cases/models fixtures? (At least for new tests)? While the global fixture approach is simpler and more convenient to get off the ground, whenever I've done this kind of thing, I've come to regret it later for exactly this reason...multiple tests wind up relying on it, and they have different needs, and they need the fixtures to evolve in differing, incompatible ways. Or you edit a global fixture to make it support a new test case and everything appears to work OK but you later discover that the fixture change prevented another test case from exercising a particular code path, allowing a regression that the fixture, as it originally exited, would not have allowed.

In RSpec's test suite, we tend to define the necessary fixtures (in our case, example groups and examples) inline within each test, so that each test can have its own isolated fixture that can evolve independently. I wonder if you could do something similar within ActiveRecord's test suite? I understand it's a harder problem since model fixtures have an external resource (a DB table) that needs to exist and be aligned with it...but it might be feasible with a little test support tooling to abstract away creating a DB table and model class in line in a single operation.

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