Stubbing global objects outside of tests cause (random) failures

Hello,

while I was debugging some randomly failed tests in discovery, I stumbled upon this code:

class SomeTest < ActionController::TestCase
  include FactImporterIsolation
  allow_transactions_for_any_importer
  # ...
end

where allow_transactions_for_any_importer stubs a global object (FactImporter.any_instance actually). Now, I am not a Ruby expert, but Mocha is supposed to clean all stubbed methods after test is finished according to docs and I confirmed this in its codebase, but when this is done outside of test block, it won’t happen - the object stays stubbed forever. Here is a fully working example:

require "mocha"
require "singleton"
require 'test/unit'
require 'mocha/test_unit'

class ASingleton
  include Singleton

  def test
    "real"
  end
end

module AStubber
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def stub_global_object
      ASingleton.any_instance.stubs(:test).returns("stubbed")
    end
  end
end

class TestOne < Test::Unit::TestCase
  def test_real
    # will fail because ASingleton is already stubbed
    assert_equal "real", ASingleton.instance.test
  end
  def test_stub
    ASingleton.any_instance.stubs(:test).returns("stubbed")
    assert_equal "stubbed", ASingleton.instance.test
  end
end

class TestTwo < Test::Unit::TestCase
  include AStubber
  stub_global_object

  def test_real
    assert_equal "real", ASingleton.instance.test
  end
  def test_stub
    ASingleton.any_instance.stubs(:test).returns("stubbed")
    assert_equal "stubbed", ASingleton.instance.test
  end
end

This will always fail because global objects are not destroyed:

MOCHA_OPTIONS=debug ruby mocha_test.rb -v

Since Rails does lazy loading, if this is also active during testing, this could be reason of some random failures.

This particular case needs to be fixed, now I wonder if we are able to detect such stubs at runtime and error out early to detect other possible probems and avoid regressions. If you know there is such a feature in Mocha, let’s try that. If there is none, we need one:

https://github.com/freerange/mocha/issues/326

1 Like

Upstream merged a change where mocha errors out when there is a mock outside of a test context.

@Shimon_Shtein what is the status of ensure_no_active_transaction stubbing fix please? I thought you are working on some change. I’d be interested in this, this errors out also if you start tests outside of rake, something like:

FOREMAN_NO_DEPRECATIONS=1 DISABLE_SPRING=true TESTOPTS=-v bundle exec ruby -Itest test/models/host_test.rb -v

I already have a fix here. It should be enough to fix the issue.

Oh missed the PR somehow, thanks.