如何模拟在类“ A”中调用并在类“ B”中定义的函数?

时间:2019-05-29 12:19:30

标签: python mocking patch python-unittest

我正在编写一个单元测试代码来测试在A类中定义的函数“ a”,该函数调用在“ B”类中定义的函数“ b”。如何使“ a”调用b-mocking函数?

#-------------------------------------------------
class B :

    def __init__(self):
        print('hello B')

    def b(self):
        return False

#------------------------------------------------
class A :
    def __init__(self):
        print('hello A')


    def a(self,a,b):
        ret = B().b()
        if ret == True:
            return 0
        else :
            return a+b
#-----------------------------------------------
class TestA(unittest.TestCase):

    def setUp(self):
        pass

    def return_true(self):
        return True

    @patch('__main__.B')
    def test_a_in_A(self,mocked_B):
        mocked_B.b.return_value = True
        assert A().a(2,3) == 0

#---------------------------------------------
if __name__ == '__main__':
    unittest.main()


我期望断言A()。a(2,3)== 0 的输出为test OK 但实际输出为AssertionError

注意:当我运行声明A()。a(2,3)== 5 时,测试返回test OK,这意味着该模拟无法正常工作。

1 个答案:

答案 0 :(得分:1)

好的,很长的版本:模拟是指用简化形式替换某些东西。但是,您不能嘲笑未使用的东西。没有任何意义。

让我们在这里查看您的代码:

    <?= Html::beginForm(['selected'], 'post'); ?>
<?= GridView::widget([
   'dataProvider'=>$dataProvider,
   'filterModel'=>$searchModel,
   'toolbar'=>['{export}', '{toggleData}',],
    'panel'=> ['type'=>'primary',
              'after'=>$object_data->enableMakePayment =='on' ? Html::submitButton('Make Payment', array('submit'=>'actionSelected'),['class'=>'btn btn-success']):'',
            ],
            'columns'=> xxx,
            'showPageSummary'=>true,
          ]);?>
<?= Html::endForm();?>

您正在此函数内构造一个新的B(),因此它没有在嘲笑B上的测试中其他地方设置的return_value。拥有模拟对象的全部要点是您传递了模拟,并获得了可预测的行为。您不能模拟完全封装在要测试的函数中的对象。

在这里,我修改了您的代码以使用一个(可能是模拟的)B对象。我将整数参数从a,b重命名为x,y,因为它太混乱了。他们与A或B无关。

您还忘记了一些进口。

def a(self,a,b):
    ret = B().b()
    if ret == True:
        return 0
    else :
        return a+b

根据要求,以下是修订版本,对现有代码的影响较小:

import unittest
from unittest.mock import patch

class B :
    def __init__(self):
        print('hello B')

    def b(self):
        return False

class A :
    def __init__(self):
        print('hello A')

    def a(self, x, y, b):
        if b.b():
            return 0
        else:
            return x + y

class TestA(unittest.TestCase):
    def setUp(self):
        pass

    def return_true(self):
        return True

    @patch('__main__.B')
    def test_a_in_A(self,mocked_B):
        mocked_B.b.return_value = True
        assert A().a(2,3, mocked_B) == 0

if __name__ == '__main__':
    unittest.main()

我将测试更改为“ self.bb()为True”,以避免遇到未初始化return_value但仍评估为true的MagicMock对象,因为...这是一个实例,而bool(object)就是这样工作的。

在这里,您仍然必须传递将return_value设置为所需值的模拟实例,因此测试将是

class A :
    def __init__(self, b=None):
        # this instance can use a member instance of B
        self.b = b if b else B()
        print('hello A')

    def a(self, x, y):
        if self.b.b() is True:
            return 0
        else:
            return x + y

如果要模拟对象替换某些东西,则必须要替换一些东西。查找“依赖注入”可能是有帮助的,“依赖注入”是相同基本思想的另一个名称。