web-dev-qa-db-ja.com

Pythonでのメソッド呼び出しのモック

これを行う方法についてスタック交換とWebの周りを検索してきましたが、メソッドの動作をモックする方法を理解できません。 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)
_

最後の行を試行すると、「関数呼び出しに割り当てられません」というエラーが表示されます。 patch.object('openpyxl','load_workbook')を使用する必要がありますか?私はJavaをGroovyでモックすることに慣れており、それは非常に簡単です。

*編集:@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']) 
_

Config.getはside_effectパラメータで複数の戻り値を返すことに注意してください。したがって、コード内でconfig.get()が1回呼び出されると_'Value1'_が返され、2回目にconfig.get()が呼び出されると返されます。 _'Value2'_を返します。

8
EliSquared

関数callをオーバーライドすることはできませんが、関数自体はオーバーライドできます。

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

だからあなたの場合:

openpyxl.load_workbook = MagicMock(return_value=wb)
11
alxwrd

単体テストでモックしたいターゲットをインポートする必要はありません。ターゲットをモックするには patch を使用します。コードに次のインポートステートメントがあるとします:import openpyxl。次に、パッチをテストで decorator として使用できます。

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

モックオブジェクトを取得するテストメソッドに引数を追加する必要があることに注意してください。

または コンテキストマネージャ として:

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()
2
Milo