Можно ли издеваться над функцией C с помощью python?

Мне было интересно, можно ли издеваться над функцией C с помощью библиотеки Python mock и как?

Чтобы сделать unit test для функции C в Python, я использую общую библиотеку, но я не могу имитировать одну функцию, чтобы передать тест. Тесты отлично работают, когда нет необходимости использовать mock.

Итак, мой вопрос: возможно ли издеваться над функцией C с использованием Python mock и как?

Вот пример исходного кода.

//read_sensor.c
   #include <stdint.h>
   #include "read_sensor.h"        
   uint8_t read_sensor (void)
   {
       return  0xff;
   }

//event_report.c
    include <stdint.h>
    #include <string.h>
    #include "event_report.h"
    #include "read_sensor.h"


    #define TRUE 1
    #define FALSE 0

    extern char status ;
    extern uint8_t flag;

    void read_distance(void)
    {
        uint8_t count;
        uint8_t value;
        uint8_t flag_count = 0;
        for (count = 0; count < 3; count ++)
        {
            value = read_sensor();
            if ( value < 100 ) 
            {
                flag_count++;
            }  
        }

        if ( flag_count == 3) 
        {
            flag = TRUE;
        } 
        else
        {
            flag = FALSE;    
        }    
    }

и тест здесь

import ctypes
from ctypes import *
import mock
import unittest

TRUE = 1
FALSE = 0

class TestClass(unittest.TestCase):

    def setUp(self):
        print "\nSetUp\n"
        self.event=ctypes.CDLL('d:/test_pytest/test_sensor_report/event_report.so')

    def tearDown(self):
        print "tearDown\n"


    def test_1_flag_should_be_true_when_readed_distance_is_0(self):
        expected_flag = TRUE

        self.event.read_sensor = MagicMock(return_value = 0)

        #calling function under test
        result = self.event.read_distance()
        print result

        #testing assertion
        assert expected_flag == result

После проверки с помощью inspect.getmembers() я получаю следующее:

 [('_FuncPtr', <class 'ctypes._FuncPtr'>), ('__class__', <class
 'ctypes.CDLL'>), ('__delattr__', <method-wrapper '__delattr__' of
 CDLL object at 0xffa87eec>), ('__dict__', {'_FuncPtr': <class
 'ctypes._FuncPtr'>, '_handle': 1690304512, '_name':
 'd:/test_pytest/test_sensor_report/event_report.so'}),
 ('__doc__', "An instance of this class represents a loaded
  dll/shared\n    library, exporting functions using the standard C
  calling\n    convention (named 'cdecl' on Windows).\n\n    The
  exported functions can be accessed as attributes, or by\n
  indexing with the function name.  Examples:\n\n    <obj>.qsort ->
  callable object\n    <obj>['qsort'] -> callable object\n\n
  Calling the functions releases the Python GIL during the call
  and\n    reacquires it afterwards.\n    "), ('__format__',
  <built-in method __format__ of CDLL object at 0xffa87eec>),
  ('__getattr__', <bound method CDLL.__getattr__ of <CDLL
    'd:/test_pytest/test_sensor_report/event_report.so', handle
    64c00000 at ffa87eec>>), ('__getattribute__', <method-wrapper
        '__getattribute__' of CDLL object at 0xffa87eec>),
    ('__getitem__', <bound method CDLL.__getitem__ of <CDLL
     'd:/test_pytest/test_sensor_report/event_report.so', handle
     64c00000 at ffa87eec>>), ('__hash__', <method-wrapper
         '__hash__' of CDLL object at 0xffa87eec>), ('__init__',
             <bound method CDLL.__init__ of <CDLL
             'd:/test_pytest/test_sensor_report/event_report.so',
             handle 64c00000 at ffa87eec>>), ('__module__', 'ctypes'),
         ('__new__', <built-in method __new__ of type object at
          0x3d35b600>), ('__reduce__', <built-in method __reduce__ of
              CDLL object at 0xffa87eec>), ('__reduce_ex__', <built-in
                  method __reduce_ex__ of CDLL object at 0xffa87eec>),
              ('__repr__', <bound method CDLL.__repr__ of <CDLL
                'd:/test_pytest/test_sensor_report/event_report.so',
                handle 64c00000 at ffa87eec>>), ('__setattr__',
                    <method-wrapper '__setattr__' of CDLL object at
                    0xffa87eec>), ('__sizeof__', <built-in method
                        __sizeof__ of CDLL object at 0xffa87eec>),
                    ('__str__', <method-wrapper '__str__' of CDLL object
                     at 0xffa87eec>), ('__subclasshook__', <built-in
                         method __subclasshook__ of type object at
                         0xffae8204>), ('__weakref__', None),
                     ('_func_flags_', 1), ('_func_restype_', <class
                             'ctypes.c_long'>), ('_handle', 1690304512),
                     ('_name',
                      'd:/test_pytest/test_sensor_report/event_report.so')]

Ответ 1

Если вы издеваетесь над этим, вы притворяетесь надежным. Или, по крайней мере, не тестируйте издеваемую функциональность в тесте, используя макет.

Нет смысла насмехаться точно с функцией C, нет необходимости в загрузке объекта SO.

Извлеките self.event и добавьте к нему экземпляр Mock "read_sensor", используйте mock.