Python: Mock a module without importing it or needing it to exist
Question: I am using starting to use a python [mock
library](http://www.voidspace.org.uk/python/mock/index.html) for my testing. I
want to mock a module that is imported within the namespace of the module
under test without actually importing it or requiring that it exist first
(i.e. throwing an ImportError).

Suppose the following code exists:

foo.py

    
    
     import helpers
     def foo_func():
        return helpers.helper_func()
    

The goal is to test foo_func() when 'helpers.py' does not exist anywhere, and
if it does exist, act as if it doesn't.

First try, using the super cool @patch decorator:

    
    
    from mock import patch, sentinel
    import foo
    @patch("foo.helpers")
    def foo_test(mock):
        mock.helper_func.return_value = sentinel.foobar
        assert foo.foo_func() == sentinel.foobar
    

This works if the "helpers" module can be imported. If it doesn't exist, I get
an ImportError.

Next attempt with patch, sans decorator:

    
    
    from mock import patch, sentinel, Mock
    import foo
    helpers_mock = patch("foo.helpers")
    helpers_mock.start()
    
    def foo_test():
        helpers_mock.helper_func = Mock('helper_func')
        helpers_mock.helper_func.return_value = sentinel.foobar
        assert foo.foo_func() == sentinel.foobar
    

Again, this doesn't work if "helpers" is missing... and, if it exists, the
assertion fails. Not really sure why that happens.

Third attempt, current solution:

    
    
    import sys
    helpers_mock = Mock(name="helpers_mock", spec=['helper_func'])
    helpers_mock.__name__ = 'helpers'
    sys.modules['helpers'] = helpers_mock
    import foo
    def foo_test():
        helpers_mock.helper_func.return_value = sentinel.foobar
        assert foo.foo_func() == sentinel.foobar
    

This test passes regardless of whether or not "helpers.py" exists.

Is this the best way to accomplish this goal? Does the mocking library I am
using provide an alternative to this? What other ways can I do this?


Answer: You're kind of missing the point of what a Mock is. You're supposed to build
them when you want an object with a particular interface, regardless of how
it's implemented.

What you're doing is trying to re-implement python's module system, plus it's
a pretty horrible abuse of global variables to boot.

Instead of making foo a module, make a Foo class, and pass in the helpers in
the constructor.

    
    
    class Foo(object):
        def __init__(self, helpers):
            self.helpers = helpers
    
    # then, instead of import foo:
    foo = Foo(mock_helpers)
    

Even if the real "helpers" is actually going to be a module, there is no
reason you need to be messing with sys.modules and setting it up via `import`
in your tests.

And if foo has to be a module, that's fine too, but you do it like this:

    
    
    # foo.py
    class Foo(object):
        pass # same code as before, plus foo_func
    
    try:
       import whatever
       _singleton = Foo(whatever)
    except ImportError:
       _singleton = Foo(something_else)
    
    def foo_func():
       return _singleton.foo_func()
    

Large chunks of the standard library work this way. It's pretty much the
standard for defining singleton-like modules.

