我可以在setUpClass中模拟多测试用例吗?

时间:2019-01-16 07:17:46

标签: python unit-testing mocking

我在每个测试用例中都使用模拟装饰器。我可以将装饰器合并到setUpClass吗?

我的单元测试就像:

    class TestCase():
        @mock.patch('some.path.config')
        def test_case_001(self, mock_cfg):
            mock_cfg.return_value = 'value'
            ...

        @mock.patch('some.path.config')
        def test_case_002(self, mock_cfg):
            mock_cfg.return_value = 'value'
            ...
        @mock.patch('some.path.config')
        def test_case_003(self, mock_cfg):
            mock_cfg.return_value = 'value'
            ...

我可以像这样将模拟合并到一个吗

    class TestCase():
        @mock.patch('some.path.config')
        @classmethod
        def setUpClass(cls, mock_cfg):
            mock_cfg.return_value = 'value'
            pass

        def test_case_001(self):
            pass

        def test_case_002(self):
            pass

        def test_case_003(self):
            pass

3 个答案:

答案 0 :(得分:0)

只需设置模拟并使用self

class TestName(TestCase):
    @mock.patch('some.path.config')
    def setUp(self, mock_cfg):
        self.mock_cfg = mock_cfg
        self.mock_cfg.return_value = 'value'
        ...

    def test_case_001(self):
        ... # use self.mock_cfg

    def test_case_002(self):
        ... # use self.mock_cfg

    ...

答案 1 :(得分:0)

使用这种方法应该很有用。

class TestDemo(test.TestCase):
    def setUp(self):
        super(TestDemo, self).setUp()
        self.mocks = [(mock.patch('a.methodB',
                                mock.MagicMock(return_value=None)))]
        for single_mock in self.mocks:
            single_mock.start()
            self.addCleanup(single_mock.stop)

答案 2 :(得分:0)

有不同的方法可以做到这一点。以下是我目前在python2和python3上都使用的技巧。

假设我们要模拟名为get_val的函数以返回yes

# data.py

def get_val():
    return 'no'

我将仅在演示代码中使用setUp,但同样的技巧也应与setUpClass一起使用。

1。最简单的方法:在测试类上使用模拟

# test_data.py

# mock value is fixed
@patch('data.get_val', MagicMock(return_value='yes'))  # fixed value
class TestFoo(TestCase):
    def setUp(self):
        print(data.get_val())   # no

    def test_case(self):
        print(data.get_val())   # yes

# mock value set by each test case
@patch('data.get_val')
class TestBar(TestCase):
    def setUp(self):
        print(data.get_val())   # no

    def test_case(self, mock_get_val):
        mock_get_val.return_value = 'yes'  # set value in each case
        print(data.get_val())   # yes

优点:

  • 最简单

缺点:

  • setUp中未模拟目标
  • 您只能选择模拟具有固定值的目标,或者在每个测试用例中提供模拟值。完全没有混合使用。

2。最灵活的方法:手动启动模拟

# test_data.py

class TestCool(TestCase):
    def setUp(self):
        self.mocks = [patch('data.get_val', MagicMock(return_value='yes'))]  # fixed value
        for mock in self.mocks:
            mock.start()
        print(data.get_val())   # yes

    def tearDown(self):
        for mock in self.mocks:
            mock.stop()

    def test_case(self):
        print(data.get_val())   # yes

    def test_case_cool(self):
        self.mocks[0].return_value = 'cool'  # override the mock only for this case
        print(data.get_val())   # cool

优点:

  • 您可以在setUp s内获得模拟作品
  • 您可以将模拟的使用与预先提供的固定值混合使用,或在每个测试用例的基础上提供模拟值
  • 您可以编写代码来控制大量模拟,因此更易于管理。

缺点:

  • 即使是简单的任务,也不得不编写更多的代码。

奖金提示:

请勿直接在patch上使用setUp,因为修改setUp的签名会导致PyCharm抱怨:

  

方法'TestMockedSetup.setUp()'的签名与类'TestCase'中的基本方法的签名不匹配

更严重的是,该模拟只能在setUp内运行,并且会在测试用例中恢复为未模拟,这可能不是您想要的。