Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock RPi.GPIO in python

I'm attempting to mock RPi.GPIO in python code to do some unit testing.

The problem I have is that my import of RPi.GPIO fails when called in my unit tests which do not run on the actual Raspberry Pi.

e.g.

tests.py

import iohandler
...
...

iohandler.py

import RPi.GPIO

def function_to_test():
    pass

The problem here is that for tests to run it must import iohandler which in turn must import RPi.GPIO. This fails as RPi.GPIO is not installed on the machine which will run the tests.

I've attempted to try and trick the modules after looking at another answer on this site as follows:

tests.py

import sys
import gpiomock # this is a file on the file system
sys.modules["RPi.GPIO"] = gpiomock.GPIO()

import iohandler # the .py file that contains the actual GPIO import

gpiomock.py

class GPIO():
    ...
    ...

As sys.modules is just a dictionary I would have thought this would work as I am providing a key for lookup of RPi.GPIO and also what I want to replace it with. However I get the following error message.

ImportError: No module named RPi.GPIO

It feels like the nested structure of the actual RPi.GPIO library is causing this not to work.

Any suggestions on how I can make this work?

like image 892
Remotec Avatar asked Aug 16 '18 14:08

Remotec


People also ask

What is RPi GPIO Python?

Raspberry-gpio-python or RPi. GPIO, is a Python module to control the GPIO interface on the Raspberry Pi. It was developed by Ben Croston and released under an MIT free software license. The project Wiki has documentation including example programs.

Is RPi GPIO installed by default?

GPIO Zero is installed by default in the Raspberry Pi OS desktop image, and the Raspberry Pi Desktop image for PC/Mac, both available from raspberrypi.org.

What is the difference between GPIO and GPIOZero?

GPIO are used to turn on the LED, but in terms of simplicity, the GPIOZero is relatively easy and requires minimum lines code to turn on the LED. It is because the GPIOZero has a module which is already imported at the start of a code and it will always use the Broadcom GPIO numbering system to identify the GPIO pins.


1 Answers

Managed to get this working by using this example from Reddit which I will reproduce below:

https://www.reddit.com/r/Python/comments/5eddp5/mock_testing_rpigpio/#ampf=undefined

tests.py

from mock import MagicMock, patch

MockRPi = MagicMock()
modules = {
    "RPi": MockRPi,
    "RPi.GPIO": MockRPi.GPIO,
}
patcher = patch.dict("sys.modules", modules)
patcher.start()

# Then for the actual test

with patch("RPi.GPIO.output") as mock_gpio:

    # Invoke the code to test GPIO
    mock_gpio.assert_called_with(....)
like image 114
Remotec Avatar answered Oct 13 '22 19:10

Remotec