在 Python 中模拟方法调用

问题描述

我一直在搜索堆栈交换并在网络上搜索如何做到这一点,但我不明白如何模拟方法的行为.我正在尝试为我的自定义类模拟 openpyxl 行为和行为.这是我的尝试:

导入单元测试从 unittest.mock 导入 MagicMock导入openpyxl从 MyPythonFile 导入 MyClass类TestMyClass(unittest.TestCase):def test_myclass(self):我的班级 = 我的班级()wb = openpyxl.workbook()ws = openpyxl.worksheet()wbPath = 'wbPath'openpyxl.load_workbook(wbPath, data_only = True) = MagicMock(return_value=wb)

当我尝试最后一行时,我收到错误无法分配给函数调用".我需要使用 patch.object('openpyxl','load_workbook') 吗?我习惯用 Groovy 在 Java 中进行模拟,它非常简单.

*想根据@alxwrd 的响应添加测试的最终版本

导入单元测试从 unittest.mock 导入 MagicMock导入openpyxl导入配置解析器从 MyPythonFile 导入 MyClass类TestMyClass(unittest.TestCase):def test_myclass(self):我的班级 = 我的班级()wb = openpyxl.workbook()ws = openpyxl.worksheet()config = configparser.ConfigParser()openpyxl.load_workbook = MagicMock(return_value=wb)wb.get_sheet_by_name = MagicMock(return_value=ws)config.sections() = MagicMock(return_value=['Section1'])config.get = MagicMock(side_effect=['Value1','Value2'])

请注意 config.get 使用 side_effect 参数提供多个返回,因此如果在代码中调用 config.get() 一次,它会返回 'Value1' 以及何时config.get() 在返回 'Value2' 时被第二次调用.

解决方案

你不能重写函数调用,但你可以重写函数本身.

来自 docs:

<块引用>

>>>从 unittest.mock 导入 MagicMock>>>东西=生产类()>>>thing.method = MagicMock(return_value=3)>>>thing.method(3, 4, 5, key='value')3>>>thing.method.assert_call_with(3, 4, 5, key='value')

所以在你的情况下:

openpyxl.load_workbook = MagicMock(return_value=wb)

I have been searching stack exchange and around the web for how to do this, but I cannot understand how to mock behaviors for methods. I am trying to mock openpyxl behaviors and behaviors for my custom class. Here is my attempt:

import unittest
from unittest.mock import MagicMock
import openpyxl 
from MyPythonFile import MyClass

class TestMyClass(unittest.TestCase):
  def test_myclass(self):
    myclass = MyClass()
    wb = openpyxl.workbook()
    ws = openpyxl.worksheet()
    wbPath = 'wbPath'

    openpyxl.load_workbook(wbPath, data_only = True) = MagicMock(return_value=wb)

When I try the final line I get the error "can't assign to function call". Do I need to use patch.object('openpyxl','load_workbook')? I am used to mocking in Java with Groovy and it's pretty straightforward.

*Edit: wanted to add the finalized version of the test based on the response from @alxwrd

import unittest
from unittest.mock import MagicMock
import openpyxl 
import configparser
from MyPythonFile import MyClass

class TestMyClass(unittest.TestCase):
  def test_myclass(self):
    myclass = MyClass()
    wb = openpyxl.workbook()
    ws = openpyxl.worksheet()
    config = configparser.ConfigParser()

    openpyxl.load_workbook = MagicMock(return_value=wb)
    wb.get_sheet_by_name = MagicMock(return_value=ws)

    config.sections() = MagicMock(return_value=['Section1'])
    config.get = MagicMock(side_effect=['Value1','Value2']) 

Notice that config.get gives multiple returns with the side_effect parameter, so if config.get() is called once in the code it returns 'Value1' and when config.get() is called a second time it returns 'Value2'.

解决方案

You can't override a function call, but you can override the function itself.

From the docs:

>>> from unittest.mock import MagicMock
>>> thing = ProductionClass()
>>> thing.method = MagicMock(return_value=3)
>>> thing.method(3, 4, 5, key='value')
3
>>> thing.method.assert_called_with(3, 4, 5, key='value')

So in your case:

openpyxl.load_workbook = MagicMock(return_value=wb)

相关文章