I am working on software for a robot, which is normally run on the Raspberry Pi. Let's consider the imports of two files:
motor.py
(runs the motors):
from RPi import GPIO as gpio
and client.py
(communicates with the server and relays commands to the motors):
from rpi.motor import Motor
Both files are in a directory called rpi
, which contains a __init__.py
and a __main__.py
. The RPi
package cannot be installed on non-RPi devices. However, I still want to test the functionality of client.py
.
import unittest
from unittest import mock
# Location A
class TestClient(unittest.TestCase):
# Location B
setUp(self):
# Location C
pass
Originally, I tried from rpi.client import Client
at LocA, but that failed because it tried to import Motor, and then import GPIO from RPi, which doesn't exist. I also tried mock.patch("rpi.client.Motor")
at LocB (including adding mock_motor
after self
, and imported Client
at LocC, but that failed as well. I tried mocking RPi
at LocA, too, but it didn't work either.
How do you mock out a library that is not installed on your system?
With Mock you can mock magic methods but you have to define them. MagicMock has "default implementations of most of the magic methods.". If you don't need to test any magic methods, Mock is adequate and doesn't bring a lot of extraneous things into your tests.
MagicMock. MagicMock objects provide a simple mocking interface that allows you to set the return value or other behavior of the function or object creation call that you patched. This allows you to fully define the behavior of the call and avoid creating real objects, which can be onerous.
Mock is a type, and patch is a context. So you are going to pass or receive Mock instances as parameters, and apply patch contexts to blocks of code. (Lowercase 'mock' is just the name of the package.) Tests and test classes are often decorated with calls to patch.
side_effect: A function to be called whenever the Mock is called. See the side_effect attribute. Useful for raising exceptions or dynamically changing return values. The function is called with the same arguments as the mock, and unless it returns DEFAULT , the return value of this function is used as the return value.
You can use patch.dict()
to patch sys.modules
and mock RPi
module as showed in pointed documentation.
Use follow code at the top of your test module:
>>> from mock import MagicMock, patch
>>> mymodule = MagicMock()
>>> patch.dict("sys.modules", RPi=mymodule).start()
>>> from RPi import GPIO as gpio
>>> gpio
<MagicMock name='mock.GPIO' id='139664555819920'>
>>> import os
>>> os
<module 'os' from '/usr/lib/python2.7/os.pyc'>
In Python3 you have same behavior.
In your specific case use patch.dict
is little bit overkill; maybe you aren't interested in patch context and original state recover. So you can simplify it by set sys.modules["RPi"]
directly:
>>> from unittest.mock import MagicMock
>>> mymodule = MagicMock()
>>> import sys
>>> sys.modules["RPi"] = mymodule
>>> from RPi import GPIO as gpio
>>> gpio
<MagicMock name='mock.GPIO' id='140511459454648'>
>>> import os
>>> os
<module 'os' from '/usr/lib/python3.4/os.py'>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With