使用Python进行单元测试中的依赖注入

Kas*_*per 4 python mocking python-unittest

我正在学习python

我想知道是否有一种机制可以将一个对象(在我的情况下是一个假对象)"注入"到被测试的类中,而无需在costructor/setter中明确添加它.

## source file
class MyBusinessClass():
    def __init__(self):
        self.__engine = RepperEngine()

    def doSomething(self):
        ## bla bla ...
        success

## test file
## fake I'd like to inkject
class MyBusinessClassFake():
   def __init__(self):
      pass

def myPrint(self) :
    print ("Hello from Mock !!!!")

class Test(unittest.TestCase):

    ## is there an automatic mechanism to inject MyBusinessClassFake 
    ## into MyBusinessClass without costructor/setter?
    def test_XXXXX_whenYYYYYY(self):

        unit = MyBusinessClass()
        unit.doSomething()
        self.assertTrue(.....)
Run Code Online (Sandbox Code Playgroud)

在我的测试中,我想"注入"对象"引擎",而不是在构造函数中传递它.我尝试了很少的选项(例如:@patch ......)没有成功.

Dan*_*Dan 5

Python中不需要IOC.这是一个Pythonic方法.

class MyBusinessClass(object):
    def __init__(self, engine=None):
        self._engine = engine or RepperEngine() 
        # Note: _engine doesn't exist until constructor is called.

    def doSomething(self):
        ## bla bla ...
        success

class Test(unittest.TestCase):

    def test_XXXXX_whenYYYYYY(self):
        mock_engine = mock.create_autospec(RepperEngine)
        unit = MyBusinessClass(mock_engine)
        unit.doSomething()
        self.assertTrue(.....)
Run Code Online (Sandbox Code Playgroud)

您还可以将该类存根以绕过构造器

class MyBusinessClassFake(MyBusinessClass):
   def __init__(self):  # we bypass super's init here
      self._engine = None
Run Code Online (Sandbox Code Playgroud)

然后在你的设置中

def setUp(self):
  self.helper = MyBusinessClassFake()
Run Code Online (Sandbox Code Playgroud)

现在,在测试中,您可以使用上下文管理器.

def test_XXXXX_whenYYYYYY(self):
  with mock.patch.object(self.helper, '_engine', autospec=True) as mock_eng:
     ...
Run Code Online (Sandbox Code Playgroud)

如果要使用constuctor注入它,则可以将其添加为类属性.

class MyBusinessClass():
    _engine = None
    def __init__(self):
        self._engine = RepperEngine() 
Run Code Online (Sandbox Code Playgroud)

现在存根绕过__init__:

class MyBusinessClassFake(MyBusinessClass):
   def __init__(self):
      pass
Run Code Online (Sandbox Code Playgroud)

现在您可以简单地分配值:

unit = MyBusinessClassFake()
unit._engine = mock.create_autospec(RepperEngine)
Run Code Online (Sandbox Code Playgroud)