Discovery
Found while fixing the SSO-migration test suite in #9686.
autobot-slm-backend/conftest.py pre-stubs submodules like services.encryption as MagicMock() in sys.modules. This creates a subtle trap: unittest.mock.patch("services.encryption.encrypt_data") resolves services.encryption via getattr(sys.modules["services"], "encryption") — an auto-generated child mock — which is a different object than sys.modules["services.encryption"]. But production code's from services.encryption import encrypt_data reads the latter. Result: the patch silently does nothing and the test asserts against an unpatched MagicMock (false green or confusing failure).
Reproduction (from #9686)
patch("services.encryption.encrypt_data", side_effect=...) left sys.modules["services.encryption"].encrypt_data unpatched; the migration kept calling the raw stub. The working fix was patch.object(sys.modules["services.encryption"], "encrypt_data", ...).
Impact
- Low/narrow today (only the migration test hit it; now fixed), but it's a latent footgun for any future test that
patch("services.<stubbed>.<fn>").
Proposed resolution
Either (a) document the gotcha in conftest.py with the patch.object(sys.modules[...]) workaround, or (b) make the stub set the submodule as an attribute on the parent services mock so the two resolution paths converge.
Cross-ref
Pattern fixed in PR for #9686 (test now 18/18 deterministic).
Discovery
Found while fixing the SSO-migration test suite in #9686.
autobot-slm-backend/conftest.pypre-stubs submodules likeservices.encryptionasMagicMock()insys.modules. This creates a subtle trap:unittest.mock.patch("services.encryption.encrypt_data")resolvesservices.encryptionviagetattr(sys.modules["services"], "encryption")— an auto-generated child mock — which is a different object thansys.modules["services.encryption"]. But production code'sfrom services.encryption import encrypt_datareads the latter. Result: the patch silently does nothing and the test asserts against an unpatched MagicMock (false green or confusing failure).Reproduction (from #9686)
patch("services.encryption.encrypt_data", side_effect=...)leftsys.modules["services.encryption"].encrypt_dataunpatched; the migration kept calling the raw stub. The working fix waspatch.object(sys.modules["services.encryption"], "encrypt_data", ...).Impact
patch("services.<stubbed>.<fn>").Proposed resolution
Either (a) document the gotcha in
conftest.pywith thepatch.object(sys.modules[...])workaround, or (b) make the stub set the submodule as an attribute on the parentservicesmock so the two resolution paths converge.Cross-ref
Pattern fixed in PR for #9686 (test now 18/18 deterministic).