模拟方法调用Python

Eli*_*red 6 python methods unit-testing mocking configparser

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

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)
Run Code Online (Sandbox Code Playgroud)

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

*编辑:想要根据@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']) 
Run Code Online (Sandbox Code Playgroud)

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

alx*_*wrd 11

您不能覆盖函数调用,但可以覆盖函数本身.

来自文档:

>>> 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')
Run Code Online (Sandbox Code Playgroud)

所以在你的情况下:

openpyxl.load_workbook = MagicMock(return_value=wb)
Run Code Online (Sandbox Code Playgroud)

  • 查找 MagicMock 对象的 side_effect。您将其设置为函数,而 return_value 设置为显式值。您可以使用 *args 作为参数定义函数,并在函数体中检查它并根据 args 值返回。 (3认同)

Mil*_*ilo 5

您不必在单元测试中导入要模拟的目标。使用patch来模拟目标。假设您的代码具有以下 import 语句:import openpyxl。然后补丁可以在您的测试中用作装饰

import unittest
from unittest import mock
from MyPythonFile import MyClass

class TestMyClass(unittest.TestCase):

    @mock.patch('MyPythonFile.openpyxl')
    def test_myclass(self, openpyxl_mock):
        wb_dummy = 'foo'
        openpyxl_mock.load_workbook.return_value = wb_dummy

        myclass = MyClass()
        myclass.load_workbook()  # assuming this calls openpyxl.load_workbook()
Run Code Online (Sandbox Code Playgroud)

请注意,您必须向测试方法添加一个参数,该方法将获取模拟对象。

或者作为上下文管理器

import unittest
from unittest import mock
from MyPythonFile import MyClass

class TestMyClass(unittest.TestCase):

    def test_myclass(self):
        with mock.patch('MyPythonFile.openpyxl') as openpyxl_mock:
            wb_dummy = 'foo'
            openpyxl_mock.load_workbook.return_value = wb_dummy

            myclass = MyClass()
            myclass.load_workbook()  # assuming this calls openpyxl.load_workbook()
Run Code Online (Sandbox Code Playgroud)