0

我有一个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从命令行成功运行。

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

@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我从不使用的参数。
  • callfourth_function而不是third_function,因为我不能使用任何类实例变量。

这两种方式打补丁有什么区别?

4

1 回答 1

0

您不需要为您正在做的事情打补丁(​​示例 A)。您正在传递参数 c,您知道它是 BasicClass 的类,因此不需要补丁。如果您在您不希望实际发生的测试函数中引入了函数调用或对象初始化,您将需要一个补丁。

使用时@patch我们应该使用 kwargside_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'})
于 2019-12-21T20:09:33.253 回答