模拟属性调用返回 MagicMock,而不是值

Eli*_*red 6 python unit-testing properties mocking

我有以下配置类:

class ConfigB(object):
  Id = None

  def __Init__(self, Id):
    self.Id = Id
Run Code Online (Sandbox Code Playgroud)

在以下类中实例化并打印属性:

from config.ConfigB import ConfigB

class FileRunner(object):
  def runProcess(self, Id)
    cfgB = ConfigB(Id)
    print(cfgB.Id)
Run Code Online (Sandbox Code Playgroud)

我创建了以下测试类来测试它,我试图在其中模拟实例化和 cfgB.Id 属性调用:

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

class TestFileRunner(unittest.TestCase):
  @mock.patch('ConfigB.ConfigB.__init__')
  @mock.patch('ConfigB.ConfigB.Id')
  def test_methodscalled(self, cfgBId, cfgBInit):


    fileRunner = FileRunner()

    cfgBId.return_value = 17

    cfgBInit.return_value = None

    print(cfgBId)

    fileRunner.runProcess(1)
Run Code Online (Sandbox Code Playgroud)

注意在调用 fileRunner 之前的 print(cfgBId) 语句。我得到以下输出:

<MagicMock name='Id' id='157297352'>
<MagicMock name='Id' id='157297352'>
Run Code Online (Sandbox Code Playgroud)

出于某种原因,当我在测试类中设置返回值时:

cfgBId.return_value = 17
Run Code Online (Sandbox Code Playgroud)

这不会在 FileRunner() 类中被调用:

print(cfgB.Id)
Run Code Online (Sandbox Code Playgroud)

我需要做什么才能正确显示我的配置属性?

另请注意,我的 'ConfigB' 类实例化比上面显示的要复杂得多,这就是为什么我要修补实例化和对 Id 属性的调用。

*更新:我已经按照@mgilson 的建议更改了我的课程,但它仍然无法正常工作:

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):

    fileRunner = FileRunner()

    cfgB.Id = 17

    print(cfgBId)

    fileRunner.runProcess(1)
Run Code Online (Sandbox Code Playgroud)

我现在从两个打印语句中得到以下输出:

<MagicMock name='ConfigB' id='157793640'>
<MagicMock name='ConfigB().Id' id='157020512'>
Run Code Online (Sandbox Code Playgroud)

任何想法为什么上述不起作用?

*解决方案:

在对@mgilson 建议的测试方法进行微小更改后,我能够使其正常工作:

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

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

    fileRunner = FileRunner()

    cfgB = MagicMock()
    cfgB.Id = 17
    #This will return the cfgB MagicMock when `ConfigB(Id)` is called in `FileRunner` class
    configB.return_value = cfgB 

    print(cfgB.Id)

    fileRunner.runProcess(1)

    #To test whether `ConfigB(17)` was called
    configB.assert_called_with(17)
Run Code Online (Sandbox Code Playgroud)

我现在得到以下输出:

<MagicMock name='ConfigB' id='157147936'>
17
Run Code Online (Sandbox Code Playgroud)

mgi*_*son 4

在我看来,最好只替换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):
    fileRunner = FileRunner()
    cfgB.return_value.Id = 17
    fileRunner.runProcess(1)
Run Code Online (Sandbox Code Playgroud)

请注意,这@mock.patch('FileRunner.ConfigB')将用模拟替换命名空间ConfigB中的类。FileRunner然后,您可以将模拟配置为执行任何您喜欢的操作 - 例如,设置Id等于 17 的值。