I have a Python project that I\'m working on in Eclipse and I have the following file structure:
/Project
/projectname
module1.py
module2.py
In my opinion the best way to handle these cases is to program via inversion of control.
In the two sections below I primarily show how a no-inversion-of-control solution would look like. The second section shows a solution with inversion of control and how this code can be tested without a mocking-framework.
In the end I state some personal pros and cons that do not at all have the intend to be correct and or complete. Feel free to comment for augmentation and correction.
You have a class that uses the std open
method from python.
class UsesOpen(object):
def some_method(self, path):
with open(path) as f:
process(f)
# how the class is being used in the open
def main():
uses_open = UsesOpen()
uses_open.some_method('/my/path')
Here I have used open
explicitly in my code, so the only way to write tests for it would be to use explicit test-data (files) or use a mocking-framework like Dunes suggests.
But there is still another way:
Now I rewrote the class differently:
class UsesOpen(object):
def __init__(self, myopen):
self.__open = myopen
def some_method(self, path):
with self.__open(path) as f:
process(f)
# how the class is being used in the open
def main():
uses_open = UsesOpen(open)
uses_open.some_method('/my/path')
In this second example I injected the dependency for open
into the constructor (Constructor Dependency Injection).
Now I can easily write tests and use my test version of open
when I need it:
EXAMPLE_CONTENT = """my file content
as an example
this can be anything"""
TEST_FILES = {
'/my/long/fake/path/to/a/file.conf': EXAMPLE_CONTENT
}
class MockFile(object):
def __init__(self, content):
self.__content = content
def read(self):
return self.__content
def __enter__(self):
return self
def __exit__(self, type, value, tb):
pass
class MockFileOpener(object):
def __init__(self, test_files):
self.__test_files = test_files
def open(self, path, *args, **kwargs):
return MockFile(self.__test_files[path])
class TestUsesOpen(object):
def test_some_method(self):
test_opener = MockFileOpener(TEST_FILES)
uses_open = UsesOpen(test_opener.open)
# assert that uses_open.some_method('/my/long/fake/path/to/a/file.conf')
# does the right thing
Pro Dependency Injection
Con Dependency Injection