簡體   English   中英

使用帶有和不帶有 side_effect 的 @patch() 模擬有什么區別?

[英]What is the difference between mocking with @patch() with and without side_effect?

我有一個script.py文件:

# in script.py
def my_basic_function(value, c):
    return c(value).words()
class BasicClass:
    def __init__(self, val):
        self.val = val
    def words():
        return self.val

和一個test.py文件:

# in test.py
from mock import patch
from script import my_basic_function, BasicClass

def third_function(self,):
    return "not {}".format(self.val)

def fourth_function():
    return "not ponies"

def init_mock(self, val):
    self.val = val

@patch('script.BasicClass.words', third_function)
@patch('script.BasicClass.__init__', init_mock)
def test_my_basic_function():
    assert my_basic_function("ponies", BasicClass) == "not ponies"

我可以成功地從命令行使用pytest test.py運行。

如果我想在我的@patch使用side_effect ,我必須做一些不同的事情:

@patch('script.BasicClass.words', side_effect = fourth_function)
@patch('script.BasicClass.__init__', init_mock)
def test_my_basic_function(amock):
    assert my_basic_function("ponies", BasicClass) == "not ponies"

即,我必須:

  • test_my_basic_function添加一個我從未使用過的參數。
  • 調用fourth_function而不是third_function ,因為我不能使用任何類實例變量。

這兩種方式打補丁有什么區別?

您不需要為您正在做的事情打補丁(示例 A )。 您正在傳入參數 c,您知道它是 BasicClass 的類,因此不需要補丁。 如果您在正在測試的函數中引入了函數調用或對象初始化,而您不想實際發生,則需要一個補丁。

使用@patch我們應該使用 kwarg side_effect來模擬引發異常,而不是調用其他函數。 如果我們想模擬函數的返回值,請使用 kwarg return_value 如果我們只想模擬一個函數,那么我們只需使用@patch而不使用任何 kwargs。 當我們使用補丁作為裝飾器時,我們需要將它們傳遞給函數。 的確,它們可以未被使用,但我們應該將它們與諸如assert_called_onceassert_called_once_with類的模擬函數一起使用,以確保您的補丁按預期工作。 請參見示例 B

==============示例A==================

import unittest


def my_basic_function(value, c):
    return c(value).words()


class BasicClass:
    def __init__(self, val):
        self.val = val

    def words(self):
        return self.val


class TestMyBasicFunction(unittest.TestCase):

    def test_my_basic_class(self):
        value = my_basic_function("jeremy", BasicClass)
        self.assertEqual("jeremy", value)

    def test_my_basic_class_wrong(self):
        value = my_basic_function("jeremy", BasicClass)
        self.assertNotEqual("w33b", value)

============示例B======================

import unittest
from unittest.mock import patch


def ensure_str(value):
    try:
        return str(value)
    except Exception:
        raise TypeError


def my_basic_function(value, c):
    value = ensure_str(value)
    return c(value).words()


class BasicClass:
    def __init__(self, val):
        self.val = val

    def words(self):
        return self.val


class TestMyBasicFunction(unittest.TestCase):

    @patch('script.ensure_str', return_value="jeremy")
    def test_return_value(self, ensure_str_mock):
        value = my_basic_function("jeremy", BasicClass)
        ensure_str_mock.assert_called_once_with("jeremy")
        self.assertEqual("jeremy", value)

    @patch('script.ensure_str')
    def test_no_return_value(self, ensure_str_mock):
        value = my_basic_function("jeremy", BasicClass)
        self.assertEqual(ensure_str_mock(), value)

    @patch('script.ensure_str', side_effect=TypeError)
    def test_side_effect(self, ensure_str_mock):
        with self.assertRaises(TypeError):
            value = my_basic_function({'apple': 'sauce'}, BasicClass)
        ensure_str_mock.assert_called_once_with({'apple': 'sauce'})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM