标签: python-mock

如何在Python中测试Celery应用程序中的Retry?

我正在尝试测试应用程序是否正在重试.

@celery.task(bind=False, default_retry_delay=30)
def convert_video(gif_url, webhook):
    // doing something
    VideoManager().convert(gif_url)
    return
    except Exception as exc:
         raise convert_video.retry(exc=exc)
Run Code Online (Sandbox Code Playgroud)

我正在嘲笑这个测试

@patch('src.video_manager.VideoManager.convert')
@patch('requests.post')
def test_retry_failed_task(self, mock_video_manager, mock_requests):
    mock_video_manager.return_value= {'webm':'file.webm', 'mp4':'file.mp4', 'ogv' : 'file.ogv', 'snapshot':'snapshot.png'}
    mock_video_manager.side_effect = Exception('some error')

    server.convert_video.retry = MagicMock()

    server.convert_video('gif_url', 'http://www.company.com/webhook?attachment_id=1234')
    server.convert_video.retry.assert_called_with(ANY)
Run Code Online (Sandbox Code Playgroud)

我收到了这个错误

TypeError:exception必须是旧式类或派生自BaseException,而不是MagicMock

这是显而易见的,但我不知道该怎么做,否则测试是否正在调用该方法.

python celery python-mock

8
推荐指数
1
解决办法
2778
查看次数

在python中模拟整个模块

我有一个从PyPI导入模块的应用程序.我想为该应用程序的源代码编写单元测试,但我不想在这些测试中使用PyPI中的模块.
我想完全模拟它(测试机器不会包含那个PyPI模块,所以任何导入都会失败).

目前,每次我尝试加载我想在单元测试中测试的类时,我都会立即收到导入错误.所以我想也许用

try: 
    except ImportError:
Run Code Online (Sandbox Code Playgroud)

并捕获该导入错误,然后使用command_module.run().这看起来非常危险/丑陋,我想知道是否还有另一种方式.

另一个想法是编写一个适配器来包装PyPI模块,但我仍在努力.

如果你知道我可以模拟整个python包,我会非常感激.谢谢.

python unit-testing python-module mocking python-mock

8
推荐指数
2
解决办法
3967
查看次数

如何模拟不存在的模块的层次结构?

让我们假设我们有一个仅在生产阶段存在的模块系统.在测试时,这些模块不存在.但我仍然想为使用这些模块的代码编写测试.我们还假设我知道如何从这些模块中模拟所有必需的对象.问题是:如何方便地将模块存根添加到当前层次结构中?

这是一个小例子.我想测试的功能放在一个名为的文件中actual.py:

actual.py:


def coolfunc():
  from level1.level2.level3_1 import thing1
  from level1.level2.level3_2 import thing2
  do_something(thing1)
  do_something_else(thing2)
Run Code Online (Sandbox Code Playgroud)

在我的测试套件中,我已经拥有了我需要的一切:我拥有thing1_mockthing2_mock.我也有测试功能.我需要的是添加level1.level2...到当前模块系统中.像这样:

tests.py

import sys
import actual

class SomeTestCase(TestCase):
  thing1_mock = mock1()
  thing2_mock = mock2()

  def setUp(self):
    sys.modules['level1'] = what should I do here?

  @patch('level1.level2.level3_1.thing1', thing1_mock)
  @patch('level1.level2.level3_1.thing1', thing2_mock)
  def test_some_case(self):
    actual.coolfunc()
Run Code Online (Sandbox Code Playgroud)

我知道我可以替换sys.modules['level1']包含另一个对象的对象,依此类推.但对我来说似乎有很多代码.我认为必须有更简单,更漂亮的解决方案.我找不到它.

python mocking python-mock

7
推荐指数
1
解决办法
1226
查看次数

使用mock更改函数调用的第二个结果

我有一个看起来像这样的循环:

for i in range(len(some_list)):
    response = requests.post(some_url, some_params)
    if response.status_code != HTTPOk:
       # do something
Run Code Online (Sandbox Code Playgroud)

我想做的是在循环的第二次迭代中更改requests.post的响应.从我的测试中,我知道我可以做以下事情:

mock_response = mock.Mock()
mock_response.status_code = 404
with mock.patch(mymodule.requests.post, return_value=mock_response):
   mymodule.some_function()
Run Code Online (Sandbox Code Playgroud)

但这似乎只适用于一个status_code.我看了side_effect,看起来我可以像这样遍历循环:

mock_response.side_effect = [
    mock.Mock(status_code=400), mock.Mock(status_code=200)
]
with mock.patch(mymodule.requests.post, return_value=mock_response):
   mymodule.some_function()
Run Code Online (Sandbox Code Playgroud)

但是,看起来它实际上并没有获得"正确"的状态代码.更改side_effect或return_value中的行为以正确获取我想要的行为的最佳方法是什么?我认为side_effect就是我想要的,但我不确定最好的方法是嘲笑回应.

python mocking pytest python-mock

7
推荐指数
1
解决办法
1431
查看次数

模拟不适用于模块功能

我编写了send_formatted_email格式化电子邮件主题和消息的send_email函数,然后在单独的模块中调用该函数。

现在我要测试send_formatted_email的调用send_email与预期的参数。为此,我试图模拟send_emailusing patch,但它并没有被模拟。

测试文件

@patch('app.util.send_email')
def test_send_formatted_email(self, mock_send_email):
    mock_send_email.return_value = True
    response = send_formatted_email(self.comment, to_email)
    mock_send_email.call_args_list
    ....
Run Code Online (Sandbox Code Playgroud)

视图.py

def send_formatted_email(comment, to_email):
    ...
    message = comment.comment
    subject = 'Comment posted'
    from_email = comment.user.email
    ...
    return send_email(subject, message, to_email, from_email)
Run Code Online (Sandbox Code Playgroud)

实用程序

def send_email(subject, message, to, from):
    return requests.post(
        ...
    )
Run Code Online (Sandbox Code Playgroud)

我什至尝试过,app.util.send_email = MagicMock(return_value=True)但这也不起作用。知道我做错了什么吗?

python python-2.7 python-mock python-unittest

7
推荐指数
1
解决办法
7288
查看次数

Python mock:包装实例方法

我想要什么: 确保Foowith语句中创建的所有实例都foo通过wraps=Foo.foo. 我想要这个的原因是我可以跟踪创建的所有实例call_count的方法。现在我这么说似乎有点不可能......fooFoo

>>> from mock import patch
...
... class Foo(object):
...
...     def foo(self):
...         return "foo"
...
... with patch("__main__.Foo.foo", wraps=Foo.foo) as m:
...     foo = Foo()
...     print(foo.foo())

Traceback (most recent call last):
  File "a.py", line 12, in <module>
    print(foo.foo())
  File "/disk/software/lib/python27/mock/mock.py", line 1062, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/disk/software/lib/python27/mock/mock.py", line 1132, in _mock_call
    return self._mock_wraps(*args, **kwargs)
TypeError: unbound method foo() must be …
Run Code Online (Sandbox Code Playgroud)

python-2.7 python-mock

7
推荐指数
1
解决办法
3144
查看次数

将参数传递给 side_effect 函数以在 unittest.mock 中进行修补

我在测试中使用patchfromunittest.mock来更改远程 API 调用的行为。

我有三个不同的函数,它们返回三个不同的json文件,这些文件代表要从 API 返回的模拟数据。对于每个模拟 api 调用,我将其设置side_effect为这些函数之一。这种模式不是 DRY,但我不知道如何将参数传递给函数side_effect

三个模拟 api 调用函数如下所示:

def mock_api_call_1():
    with open('path/to/mock_1.json') as f:
        mock_data = json.load(f)
    return mock_data
Run Code Online (Sandbox Code Playgroud)

这是我的测试

class MyTest(TestCase):

    def test_api(self):

        with patch('mymodule.utils.api_call', side_effect=mock_api_call_1):
            do_crud_operations()
            self.assertEqual(MyModel.objects.all().count(), 10)

        with patch('mymodule.utils.api_call', side_effect=mock_api_call_2):
            do_crud_operations()
            self.assertEqual(MyModel.objects.all().count(), 11)
Run Code Online (Sandbox Code Playgroud)

如何重构此代码以便能够将参数传递给side_effect(mock_call(1)而不是mock_call_1)。

单元测试文档中,我看到:

side_effect:每当调用 Mock 时都会调用的函数。请参阅 side_effect 属性。对于引发异常或动态更改返回值很有用。使用与模拟相同的参数调用该函数,除非它返回 DEFAULT,否则该函数的返回值将用作返回值。

我看到传递给的函数采用side_effect与模拟相同的参数,但我仍然不确定如何最好地使用模拟来完成此任务。我最终会想要添加更多的测试用例,所以我不想对不同的mock_api_call函数进行硬编码。

python unit-testing python-mock python-unittest

7
推荐指数
1
解决办法
1万
查看次数

模拟方法的返回值不起作用

在测试该create_response方法时,我似乎无法模拟该方法的返回值get_external_response

/foo/响应

from abc import ABCMeta, abstractmethod


def create_response(url, type):
    query = create_query(url, type)
    external_response = get_external_response(query)  <-- what I want to mock
    return external_response

def create_query(url, type):
    cc = MyFactory
    return cc.get_concrete_class(url, type)

def get_external_response(cc):
    return cc.make_query()


class MyAbstractClass(metaclass=ABCMeta):
    def __init__(self, url, type):
        self.url = url
        self.type = type
        self.query = self.make_query()

    @abstractmethod
    def make_query(self):
        pass

class MyFactory:
    @staticmethod
    def get_concrete_class(url, type):
        if type == 'A':
            return MyClass(url, type)
        else:
            print("not valid type")

class MyClass(MyAbstractClass): …
Run Code Online (Sandbox Code Playgroud)

mocking python-3.x python-mock

7
推荐指数
1
解决办法
9917
查看次数

patch.multiple 是否可以作为装饰器与 pytest 一起使用

我采用test_tmp.pyhttps://docs.python.org/3/library/unittest.mock.html#patch-multiple

from unittest.mock import DEFAULT, MagicMock, patch

thing = object()
other = object()

@patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)
def test_function(thing, other):
    print(f'thing={thing}')
    print(f'other={other}')
    assert isinstance(thing, MagicMock)
    assert isinstance(other, MagicMock)

test_function()
Run Code Online (Sandbox Code Playgroud)

它与 python 一起运行

python test_tmp.py
thing=<MagicMock name='thing' id='4355085552'>
other=<MagicMock name='other' id='4355243312'>
Run Code Online (Sandbox Code Playgroud)

但它不适用于 pytest 并出现类似错误

pytest test_tmp.py
============================================================================================================= test session starts =============================================================================================================
platform darwin -- Python 3.8.2, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: /private/tmp
collected 0 items / 1 error

=================================================================================================================== ERRORS ====================================================================================================================
________________________________________________________________________________________________________ ERROR collecting test_tmp.py _________________________________________________________________________________________________________
test_tmp.py:13: in <module>
    test_function() …
Run Code Online (Sandbox Code Playgroud)

python pytest python-mock

7
推荐指数
1
解决办法
2026
查看次数

将mock.patch.object 与wraps 和side_effect一起使用有什么区别吗?

下面两个测试有什么区别? (如果有的话)

**在 python 3.10 中

import unittest
from unittest.mock import Mock, patch

class Potato(object):
    def spam(self, n):
        return self.foo(n=n)

    def foo(self, n):
        return self.bar(n)

    def bar(self, n):
        return n + 2

class PotatoTest(unittest.TestCase):
    def test_side_effect(self):
        spud = Potato()
        with patch.object(spud, 'foo', side_effect=spud.foo) as mock_foo:
            forty_two = spud.spam(n=40)
            mock_foo.assert_called_once_with(n=40)
        self.assertEqual(forty_two, 42)

    def test_wraps(self):
        spud = Potato()
        with patch.object(spud, 'foo', wraps=spud.foo) as mock_foo:
            forty_two = spud.spam(n=40)
            mock_foo.assert_called_once_with(n=40)
        self.assertEqual(forty_two, 42)
Run Code Online (Sandbox Code Playgroud)

一个用于side_effect保留原始方法,而另一个用于wraps有效地做同样的事情(或者至少据我所知)。

python python-mock python-3.10

7
推荐指数
0
解决办法
679
查看次数