How to do basic dependency injection in Python (for mocking / testing)

Python is a relatively new language for me. Unit testing and dependency on injections is what I have been doing for some time, so I am familiar with it from the point of view of C #.

I recently wrote this snippet of Python code:

import requests # my dependency: http://docs.python-requests.org/en/latest/ class someClass: def __init__(self): pass def __do(self, url, datagram): return requests.post(self, url, datagram) 

And then I realized that I had just created a hard-coded dependency. Bleh.

I thought about changing my code to inject constructor dependencies:

 def __init__(self,requestLib=requests): self.__request = requestLib def __do(self, url, datagram): return self.__request.post(self, url, datagram) 

Now this allows me to introduce a fake / mock dependency for the sake of Unit Testing, but was not sure if it was considered Python-ic. So I turn to the Python community for advice.

What are some examples of Python-ic ways to make basic DI (mainly for writing Unit tests that use Mocks / Fake)?

APPENDIX For anyone interested in the layout answer, I decided to ask a separate question here: How does @ mock.patch know which parameter to use for each layout of the object?

+7
python dependency-injection unit-testing mocking
source share
2 answers

Do not do this. Just import the queries as usual and use them as usual. Passing libraries as arguments to your designers is a fun thing, but not very pyphonic and unnecessary for your purposes. To mock unit tests, use the mock library. In python 3 it is built into the standard library

https://docs.python.org/3.4/library/unittest.mock.html

And in python 2 you need to install it separately

https://pypi.python.org/pypi/mock

Your test code will look something like this (using python 3 version)

 from unittest import TestCase from unittest.mock import patch class MyTest(TestCase): @patch("mymodule.requests.post") def test_my_code(self, mock_post): # ... do my thing here... 
+6
source share

When injecting a query module, there may be too many, it is very good practice to have some dependencies as injections.

It is possible that a full-fledged structure is exactly what you need. There are excellent modules for this, such as Injector .

A more minimalist and direct approach would be to use a decorator to do the job for you. There are several modules for there .

I support one of these modules: Injectable , which provides a Python 3 @autowired decoder to provide an easy and clean dependency injection.

The highlights of this decorator are as follows:

  • function should not know about auto-pause at all
  • dependencies can be lazy initialized
  • the caller can explicitly pass dependency instances if desired

You basically turn code like this :

 def __init__(self, *, model: Model = None, service: Service = None): if model is None: model = Model() if service is None: service = Service() self.model = model self.service = service # actual code 

into this :

 @autowired def __init__(self, *, model: Model, service: Service): self.model = model self.service = service # actual code 

There are no complicated things, no settings, no workflows are running.

0
source share

All Articles