I hardly do any patching, but I believe you're patching either too late, or the wrong thing. SMTP
has already been imported, resulting in a direct reference to the original class—it will not be looked up in smtplib
anymore. Instead, you'd need to patch that reference. Let's use a more realistic example, in which you have module.py
and test_module.py
.
module.py
:
import smtplib
from smtplib import SMTP # Basically a local variable
def get_smtp_unqualified():
return SMTP # Doing a lookup in this module
def get_smtp_qualified():
return smtplib.SMTP # Doing a lookup in smtplib
test_module.py
import unittest
from unittest import patch
from module import get_smtp_unqualified, get_smtp_qualified
class ModuleTest(unittest.TestCase):
def test_get_smtp_unqualified(self):
with patch('module.SMTP') as smtp:
self.assertIs(smtp, get_smtp_unqualified())
def test_get_smtp_qualified_local(self):
with patch('module.smtplib.SMTP') as smtp:
self.assertIs(smtp, get_smtp_qualified())
def test_get_smtp_qualified_global(self):
with patch('smtplib.SMTP') as smtp:
self.assertIs(smtp, get_smtp_qualified())
As long as you patch in time before a lookup, it does what you want—3 passing tests. The very earliest time would be before importing any other modules than unittest
. Then those modules will not have imported smtplib.SMTP
yet. More on that here. It gets tricky though, when your tests are split over multiple modules.
Patching is inherently dirty. You're messing with another's internals. To make it work, you have to look on the inside. If the inside changes, tests will break. That's why you should consider it a last resort and prefer different means, such as dependency injection. That's a whole different topic, but in any case, don't rely on patching to prevent messages from going out—also change the configuration!