Python unittest import module

Introduction

This guide will give you a way to mock module/package imports when unit-testing.

Why would you want this

You are running your unit-tests in an environment where particular packages are not available. An example of such a case is if you writing your python implementation on Windows but the code runs on a Linux host. If you want to have your unit-tests run on both machines you might need to mock the module/package name.

In the examples below, I am going to use cv2 package as an example package. You can replace cv2 with any other package. (E.g. pyudev, RPi.GPIO)

How-to

Assuming you have a function that loads an image from a file using OpenCV cv2 package:

import cv2 def load_image(image_file): return cv2.imread(image_file)

Standard method – package is available

In the case where the package is available on the testing environment you would do the following:
test_foo.py

import sys import unittest from unittest.mock import MagicMock, patch import foo class TestFoo(unittest.TestCase): @patch('cv2.imread') def test_load_image(self, imread): foo.load_image('test') assert imread.called

Method 1 – No package available

If you don’t have cv2 package installed, then our test file could look like:
test_foo1.py

import sys import unittest from unittest.mock import MagicMock, patch sys.modules['cv2'] = MagicMock() import foo class TestFoo(unittest.TestCase): @patch('cv2.imread') def test_load_image(self, imread): foo.load_image('test') assert imread.called

The addition in the above scenario is that you load a MagicMock object in place of the cv2 package. Hence, when the import call of cv2 inside foo is invoked, it finds that is already loaded and does not try to find the actual package.

Читайте также:  Resolve java source named

Downside

This method has a downside that all subsequent tests have the MagicMock pre-loaded for the cv2 package. Such a scenario could happen if you run multiple tests from a folder with one command. This at first might not seem like a problem as cv2 is not available in the first place. However, if test_foo2.py is removed or its dependency to cv2 changes then other test will fail.

Method 2 – No package available

To prevent affecting other test runs, one solution is to delete the dictionary key right after importing the module under test. See below

import sys import unittest from unittest.mock import MagicMock, patch sys.modules['cv2'] = MagicMock() import foo del sys.modules['cv2'] class TestFoo(unittest.TestCase): @patch('foo.cv2.imread') def test_load_image(self, imread): foo.load_image('test') assert imread.called

With the above method you ensure that whenever a dependency to cv2 is encountered, you add the necessary imports.

Downside

The downside of this method is that you need to do this for every file you are importing a module that imports such a package (i.e. cv2 in the above case). Let alone, that you can have multiple import that don’t show the direct dependency to the package that is not available.

import module_b def foo(): pass

If you want to test module_a.py one might think that it is not dependent on the cv2 , but it is indirectly via module_b . Therefore, in such a case you might need something more generic.

Generic approach for multiple tests

Create a dummy module that mocks the module/package that is not available and in turn import that module in every test.

sys.modules['cv2'] = MagicMock() sys.modules['other_package'] = MagicMock()

Then inside your unittest file you can do the following:

import sys import unittest from unittest.mock import MagicMock, patch import mock_import import foo class TestFoo(unittest.TestCase): @patch('foo.cv2.imread') def test_load_image(self, imread): foo.load_image('test') assert imread.called

Remarks

These are methods I am currently using in a project I had this issue. I am curious to know how other people have solved similar issues, so please write your suggestions below in the comments section.

References

  • https://stackoverflow.com/questions/51879185/how-to-mock-rpi-gpio-in-python
  • https://docs.python.org/3/library/unittest.mock.html
  • https://docs.python.org/3/tutorial/modules.html

Источник

Оцените статью