在不使用mock的情况下检查函数是否已在Python unittest中调用的规范方法是什么?

时间:2014-06-02 16:08:59

标签: python unit-testing testing tdd

如果我有一个类似于下面的1的类,我想测试bar函数的各种情况,我怎样才能在不模仿私有函数的情况下完成这个?换句话说,如何在Python的unittest库中实现类似的东西:

def test_bar():
    f = Foo()
    f.bar(3)
    expect(self._is_positive_number).toBeCalled()

foo.py

class Foo():
    def bar(self, x):
       if type(x) is not int:
           print('Please enter a valid integer')
           return False

       if x > 0:
           self._is_positive_number()
       elif x == 0:
           self._is_zero()
       else 
           self._is_negative()

    def _is_positive_number(self):
        print('Positive')
        return True

    def _is_zero(self):
        print('Zero')
        return True

    def _is_negative_number(self):
        print('Negative')
        return True

2 个答案:

答案 0 :(得分:2)

据我所知,如果不嘲笑私有方法,就无法做到这一点。但是,mock库(从3.3开始在标准库中以unittest.mock形式提供,否则单独安装)使这相对无痛:

try:
    # Python 3.3 or later
    import unittest.mock as mock
except ImportError:
    # Make sure you install it first
    import mock

class TestFoo(unittest.TestCase):
    def setUp(self):
        self.f = Foo()

    def test_bar(self):
        with mock.patch.object(self.f, '_is_positive_number') as is_pos:
            self.f.bar(3)
            self.assertTrue(is_pos.called)

答案 1 :(得分:2)

使用mock库是首选方法。

这是所有三种私有方法的完整示例。如果您愿意,可以选择较短的名字,但我最好保持明确。请注意,为了安全起见,您应断言不仅调用了所需的方法,而且还调用了其他私有方法:

from unittest import TestCase
from mock import Mock


class MyTestCase(TestCase):
    def setUp(self):
        self.instance = Foo()
        self.instance._is_positive_number = Mock()
        self.instance._is_negative_number = Mock()
        self.instance._is_zero = Mock()

    def test_positive(self):
        self.instance.bar(3)
        self.assertTrue(self.instance._is_positive_number.called)
        self.assertFalse(self.instance._is_negative_number.called)
        self.assertFalse(self.instance._is_zero.called)

    def test_negative(self):
        self.instance.bar(-3)
        self.assertFalse(self.instance._is_positive_number.called)
        self.assertTrue(self.instance._is_negative_number.called)
        self.assertFalse(self.instance._is_zero.called)

    def test_zero(self):
        self.instance.bar(0)
        self.assertFalse(self.instance._is_positive_number.called)
        self.assertFalse(self.instance._is_negative_number.called)
        self.assertTrue(self.instance._is_zero.called)