I've got a codebase which is tested in two scenarios: run via entry point A, and B. When it's run via A, the db connection is used as is. When it's run via B, ActiveRecord::Base.connection
is monkey patched.
Since B is just a helper script, it's currently tested in rspec by running it as an external command and checking the output. I'd like to bring some sanity back and test the behaviour without spawning new processes though.
Is there a way in rspec mocks to "temporarily extend" a class? I'd like to get the behaviour of doing:
before do
ActiveRecord::Base.connection.extend(App::SomePatch)
end
after do
ActiveRecord::Base.connection.unextend(App::SomePatch)
end
Of course unextend doesn't exist. I have only 3 methods to patch, so I could potentially use the mocks for each method instead, but a method alias makes this complicated.
The patch module looks like this:
module SomePatch
def SomePatch.included(mod)
alias :old_execute :execute
end
def execute(*args) ... end
def some_storage
@some_storage ||= []
end
end
I would go with cloning, something along this lines:
before do
@original_connection = ActiveRecord::Base.connection
ActiveRecord::Base.connection = @original_commention.dup
ActiveRecord::Base.connection.extend(App::SomePatch)
end
after do
ActiveRecord::Base.connection = @original_connection
end
I did not test that, but as long there are not "quirks" with cloning the object, this should be fine.
Edit: Ok, this does not work, because there's no connection=
method, so you can probably try with mocking:
before do
@original_connection = ActiveRecord::Base.connection
new_connection = @original_connection.dup
new_connection.extend(App::SomePatch)
allow(ActiveRecord::Base).to receive(:connection).and_return(new_connection)
end
And you probably don't need after
because the mock will be "undone"