On Jan 10, 4:21 am, Silfheed <silfh...@gmail.com> wrote: > So I'm in the current testing situation: > > sender.py: > ------------- > def sendEmails(): > return "I send emails" > > alerter.py: > ------------- > from sender import * > def DoStuffAndSendEmails(): > doStuff() > sendEmails() > > I'm trying to write a test fn that will test DoStuffAndSendEmails() > (as well as it's kin) without actually sending any emails out. I > could go through alter alerter so that it does `import sender` and > then find and replace fn() with sender.fn() so I can just create a > mock fn fakeSendEmails() and and do something like sender.sendEmails = > fakeSendEmails, but I'd rather not. > > Anyone know how to test alerter.py with out altering the file? > > Thanks!
Don't ever put testing flag in your non-code, that's very ugly and creates a weird circular dependency between your real code and your test code. It will give you headaches later. To answer to Rob: yeah, sure that would work, but I always thought mocking the imported function didn't feel right. The test then depends on the import method of the tested module. If you later change your mind and decide to use "import sender" and then "sender.sendEmails()", you have to change your test code. In my code, I have a custom TestCase class which has a method for dealing with this stuff, here's the code relevant to your problem: class TestCase(unittest.TestCase): cls_tested_module = None def run(self, result=None): self._mocked = [] unittest.TestCase.run(self, result) # We use reversed() so the original value is put back, even if we mock twice. for target, attrname, old_value in reversed(self._mocked): setattr(target, attrname, old_value) def mock(self, target, attrname, replace_with): ''' Replaces 'target' attribute 'attrname' with 'replace_with' and put it back to normal at tearDown. The very nice thing about mock() is that it will scan self.cls_tested_module for the mock target and mock it as well. This is to fix the "from" imports problem (Where even if you mock(os, 'path'), if the tested module imported it with "from os import path", the mock will not work). ''' oldvalue = getattr(target, attrname) self._mocked.append((target, attrname, oldvalue)) setattr(target, attrname, replace_with) if (self.cls_tested_module is not None) and (self.cls_tested_module is not target): for key, value in self.cls_tested_module.__dict__.iteritems (): if value is oldvalue: self.mock(self.cls_tested_module, key, replace_with) When you use it, set cls_tested_module (at the class level) to "sender" (not the string, the module instance) -- http://mail.python.org/mailman/listinfo/python-list