Python模拟一个依赖对象

时间:2017-07-20 09:48:25

标签: python unit-testing mocking

我有一个python类(MyClass)我是单元测试。它有一个创建数据库的外部依赖项,我想模拟该对象并检查它是否被调用。

from entities_database import DBCreator

class MyClass():

    def __init__(self):
        self.db = DBCreator()

    def create(self, name):
        value = self.db.create_db(name)

我想测试init函数,所以看看一个模拟的DBCreator被调用。然后测试create函数以检查是否使用" name"来调用create_db(),并返回" name"重视。

我不知道该怎么做,到目前为止我有这个:

from entities_database import DBCreator
from test_unit import MyClass
import unittest
import mock


class MyClassTest(unittest.TestCase):

    @mock.patch('entities_database.DBCreator', autospec=True)
    def test_myclass_init(self, dbcreator_mock):
        creator = mock.create_autospec(DBCreator)
        dbcreator_mock.return_value = creator

        myclass = MyClass()
        assert(dbcreator_mock.called)

结果是:

F
======================================================================
FAIL: test_myclass_init (unit_test.MyClassTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/paul/Data/TSC/Code/parltrack_eu/venv/lib/python3.6/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/Users/paul/Data/TSC/Code/parltrack_eu/unit_test.py", line 32, in test_myclass_init
    assert(dbcreator_mock.called)
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.036s

FAILED (failures=1)

如何修复我的代码?

----更新---- 除了下面的依赖注入解决方案之外,还可以使用补丁执行以下操作,如下所示@Goyo

from entities_database import DBCreator
from test_unit import MyClass
import unittest
import mock


class MyClassTest(unittest.TestCase):

    @mock.patch('test_unit.DBCreator', autospec=True)
    def test_myclass_init(self, mock_db):
        '''
        Test the initialization of MyClass
        Test that DBCreator is initialized
        '''
        creator = mock.create_autospec(DBCreator)
        mock_db.return_value = creator

        # Assert that the DBCreator is initialised
        myclass = MyClass()
        assert(mock_db.called)

    @mock.patch('test_unit.DBCreator', autospec=True)
    def test_myclass_create(self, mock_db):
        '''
        Test the myclass.create() function
        and assert it calls db.create_db() with the correct
        argument
        '''
        name = 'unittest'
        myclass = MyClass()
        myclass.create(name)
        # Assert that create_db was called with name
        myclass.db.create_db.assert_called_with(name)

2 个答案:

答案 0 :(得分:2)

补丁很棘手。您必须在SUT将查找的同一命名空间中修补对象。在这种情况下,您可能需要@mock.patch('test_unit.DBCreator', autospec=True)

使用依赖注入避免了这种问题,并使事情变得更加明确和清晰:

class MyClass():

    def __init__(self, db):
        self.db = db

    def create(self, name):
        value = self.db.create_db(name)

然后在你的测试中:

class MyClassTest(unittest.TestCase):
    def test_myclass_init(self):
        db = mock.Mock()
        myclass = MyClass(db)
        self.assertEqual(myclass.db, db)

    def test_myclass_create(self):
        db = mock.Mock()
        myclass = MyClass(db)
        name = mock.Mock()
        myclass.create(name)
        myclass.db.create_db.assert_called_once_with(name)

答案 1 :(得分:0)

我无法尝试使用您的示例代码。但是你应该尝试模拟create_db函数而不是DBCreator类。