模拟一个类并返回多个值

时间:2017-06-19 13:25:25

标签: python mocking side-effects

我有以下配置类:

class ConfigB(object):
  Id = None
  fileName = None

  def __init__(self, file):
    self.Id = self.searchForId(file)
    self.fileName = file

在以下类中多次实例化并访问了属性:

from config.ConfigB import ConfigB

class FileRunner(object):
  def runProcess(self, cfgA)
    for file in cfgA.listFiles:
       cfgB = ConfigB(file)
       print(cfgB.Id)
       print(cfgB.fileName)

为了测试它,我创建了以下测试类,我在其中模拟了FileRunner类的ConfigB:

import unittest
import unittest.mock imort MagicMock
import mock
from FileRunner import FileRunner

class TestFileRunner(unittest.TestCase):
  @mock.patch('FileRunner.ConfigB')
  def test_methodscalled(self, cfgB):

    cfgA = Mock()
    cfgA.listFiles = ['File1','File2']

    cfgB().Id.side_effect = [1,2]
    cfgB().fileName.side_effect = ['File1','File2']

    fileRunner = FileRunner()


    fileRunner.runProcess(cfgA)

我试图让cfgB的模拟为两个' Id'返回多个值。和' fileName'。如果我使用cfgB().fileName = 'File1',我可以让cfgB的模拟返回' File1'两次,但我更愿意,如果我可以迭代多个返回值。有什么可以做的吗?

*编辑:我想说明上述测试不能用于返回特定值,而是我得到以下输出:

<MagicMock name='cfgB().Id' id='160833320'>
<MagicMock name='cfgB().fileName' id='160833320'>
<MagicMock name='cfgB().Id' id='160833320'>
<MagicMock name='cfgB().fileName' id='160833320'>

1 个答案:

答案 0 :(得分:1)

这里的问题是您实际上并没有按照预期的方式使用side_effect

根据文档hereside_effect属性声明:

  

调用Mock时要调用的函数。见   side_effect属性。用于引发异常或动态   改变回报值。使用相同的参数调用该函数   作为模拟,除非它返回DEFAULT,否则返回此值   函数用作返回值。

这里要实现的关键是功能。这里的期望实际上是所谓的。实际上,您正在测试属性,并且不像函数一样调用属性,因此您实际上并没有正确配置测试以及使用这些side_effect调用的方式。

根据您要测试的内容,您应该采取稍微不同的方法。查看代码,在迭代ConfigB时,您希望在循环内创建一个cfgA.listFiles对象。因此,这表明您实际上希望控制side_effect当您在测试中将ConfigB(file)模拟为cfgB时调用的cfgA.listFiles

此外,您正在传递从configB迭代到listFiles的文件名。因此,您只需将cfgA.listFiles = ['some_file_name_1', 'some_file_name_2'] 设置为任意文件名列表:

cfgB

然后,您需要做的就是设置Mock模拟的side_effect现在返回一个包含感兴趣属性的cfgB.side_effect = [ Mock(Id="some_id_1", fileName="some_filename_1"), Mock(Id="some_id_2", fileName="some_filename_2") ] 对象,以便正确地进行测试,因此:

some_id_1
some_filename_1
some_id_2
some_filename_2

运行这些修改后,您将从代码中的print语句中产生以下结果:

side_effect

因此,正如您所看到的,现在我们已成功设置您的iterable以保存您要为测试设置的文件名。此外,ConfigB现在可以在模拟class TestFileRunner(unittest.TestCase): @mock.patch('FileRunner.ConfigB') def test_methodscalled(self, cfgB): cfgA = Mock() cfgA.listFiles = ['some_file_name_1', 'some_file_name_2'] cfgB.side_effect = [ Mock(Id="some_id_1", fileName="some_filename_1"), Mock(Id="some_id_2", fileName="some_filename_2") ] fileRunner = FileRunner() fileRunner.runProcess(cfgA) 时正确使用,以便现在返回正确的模拟配置对象,其中包含您可以在每次迭代中测试的属性。

以下是最终测试方法的全部内容:

java -cp /home/Blake Main arg1 arg2 arg3