Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unittest GPIO output value of raspberry pi in Python

I am making Raspberry Pi program by using python. I want to write unittest of my python code. How can I get output status of GPIO?

test target class is bellow. I want to check outputs after calling stop, brake, rotateClockwise and rotateCounterClockwise.

import RPi.GPIO as GPIO
# moter management class, with like TA7291P
class MoterManager:
    def __init__(self, in1Pin, in2Pin):
        self.__in1Pin = in1Pin
        self.__in2Pin = in2Pin

    def stop(self):
        self.__offIn1()
        self.__offIn2()

    def brake(self):
        elf.__onIn1()
        self.__onIn2()

    def rotateClockwise(self):
        self.__onIn1()
        self.__offIn2()

    def rotateCounterClockwise(self):
        self.__offIn1()
        self.__onIn2()

    def __onIn1(self):
        GPIO.output( self.__in1Pin, True)
        print "In1 on"

    def __onIn2(self):
        GPIO.output( self.__in2Pin, True)
        print "In2 on"

    def __offIn1(self):
        GPIO.output( self.__in1Pin, False )
        print "In1 off"

    def __offIn2(self):
        GPIO.output( self.__in2Pin, False )
        print "In2 off"
like image 353
Yuichi Shiga Avatar asked Sep 29 '22 15:09

Yuichi Shiga


1 Answers

If you trust RPi.GPIO library, I think it is a good stating point, you can patch it by unittest.mock framework. patch RPi.GPIO.output give to you the possibility to break the dependency from HW and sense the calls to that function.

That could be your test class

import unittest
from unittest.mock import patch, call
from my_module import MoterManager

@patch("RPi.GPIO.output", autospec=True)
class TestMoterManager(unittest.TestClass):
    in1Pin=67
    in2Pin=68

    def test_init(self, mock_output):
        """If you would MoterManager() stop motor when you build it your test looks like follow code"""
        mm = MoterManager(self.in1Pin,self.in1Pin)
        mock_output.assert_has_calls([call(self.in1Pin, False),call(self.in2Pin, False)],any_order=True)

    def test_stop(self, mock_output):
        mm = MoterManager(self.in1Pin,self.in1Pin)
        mock_output.reset_mock
        mm.stop()
        mock_output.assert_has_calls([call(self.in1Pin, False),call(self.in2Pin, False)],any_order=True)

    def test_brake(self, mock_output):
        mm = MoterManager(self.in1Pin,self.in1Pin)
        mock_output.reset_mock
        mm.stop()
        mock_output.assert_has_calls([call(self.in1Pin, True),call(self.in2Pin, True)],any_order=True)

    def test_rotateClockwise(self, mock_output):
        mm = MoterManager(self.in1Pin,self.in1Pin)
        mock_output.reset_mock
        mm.stop()
        mock_output.assert_has_calls([call(self.in1Pin, True),call(self.in2Pin, False)],any_order=True)

    def test_rotateCounterClockwise(self, mock_output):
        mm = MoterManager(self.in1Pin,self.in1Pin)
        mock_output.reset_mock
        mm.stop()
        mock_output.assert_has_calls([call(self.in1Pin, False),call(self.in2Pin, True)],any_order=True)

Few notes:

  • In python-2.7 use mock available by pip instead of unittest.mock
  • I'm using autospec=True almost in every test if you are wondering why take a look this
  • My tests should raise almost 1 bug in your code: typo in brake method
like image 165
Michele d'Amico Avatar answered Oct 07 '22 20:10

Michele d'Amico