Ivo*_*ijk 22 python unit-testing mocking python-mock
我有一个基类,它定义了一个类属性和一些依赖它的子类,例如
class Base(object):
assignment = dict(a=1, b=2, c=3)
Run Code Online (Sandbox Code Playgroud)
我想用不同的任务对这个类进行单元测试,例如空字典,单项等.当然,这非常简化,不是重构我的类或测试的问题.
我得到的(pytest)测试,最终,工作是
from .base import Base
def test_empty(self):
with mock.patch("base.Base.assignment") as a:
a.__get__ = mock.Mock(return_value={})
assert len(Base().assignment.values()) == 0
def test_single(self):
with mock.patch("base.Base.assignment") as a:
a.__get__ = mock.Mock(return_value={'a':1})
assert len(Base().assignment.values()) == 1
Run Code Online (Sandbox Code Playgroud)
这感觉相当复杂和hacky - 我甚至不完全理解为什么它工作(虽然我熟悉描述符).mock会自动将类属性转换为描述符吗?
一种感觉更符合逻辑的解决方案不起作用:
def test_single(self):
with mock.patch("base.Base") as a:
a.assignment = mock.PropertyMock(return_value={'a':1})
assert len(Base().assignment.values()) == 1
Run Code Online (Sandbox Code Playgroud)
要不就
def test_single(self):
with mock.patch("base.Base") as a:
a.assignment = {'a':1}
assert len(Base().assignment.values()) == 1
Run Code Online (Sandbox Code Playgroud)
我尝试过的其他变种也不起作用(测试中的作业保持不变).
模拟类属性的正确方法是什么?有没有比上面更好/更容易理解的方式?
Mar*_*ers 20
base.Base.assignment简单地用一个Mock对象替换.您提出通过添加它描述__get__方法.
它有点冗长,有点不必要; 你可以直接设置base.Base.assignment:
def test_empty(self):
Base.assignment = {}
assert len(Base().assignment.values()) == 0
Run Code Online (Sandbox Code Playgroud)
当然,使用测试并发时这不太安全.
要使用a PropertyMock,我会使用:
with patch('base.Base.assignment', new_callable=PropertyMock) as a:
a.return_value = {'a': 1}
Run Code Online (Sandbox Code Playgroud)
甚至:
with patch('base.Base.assignment', new_callable=PropertyMock,
return_value={'a': 1}):
Run Code Online (Sandbox Code Playgroud)
也许我遗漏了一些东西,但是如果不使用,PropertyMock难道这不可能吗?
with mock.patch.object(Base, 'assignment', {'bucket': 'head'}):
# do stuff
Run Code Online (Sandbox Code Playgroud)
以下是如何对您的类进行单元测试的示例Base:
dict和int) @patch装饰器和框架。pytestpython 2.7+3+# -*- coding: utf-8 -*-
try: #python 3
from unittest.mock import patch, PropertyMock
except ImportError as e: #python 2
from mock import patch, PropertyMock
from base import Base
@patch('base.Base.assign_dict', new_callable=PropertyMock, return_value=dict(a=1, b=2, c=3))
@patch('base.Base.assign_int', new_callable=PropertyMock, return_value=9765)
def test_type(mock_dict, mock_int):
"""Test if mocked class attributes have correct types"""
assert isinstance(Base().assign_dict, dict)
assert isinstance(Base().assign_int , int)
Run Code Online (Sandbox Code Playgroud)
为了提高可读性,您可以使用@patch装饰器:
from mock import patch
from unittest import TestCase
from base import Base
class MyTest(TestCase):
@patch('base.Base.assignment')
def test_empty(self, mock_assignment):
# The `mock_assignment` is a MagicMock instance,
# you can do whatever you want to it.
mock_assignment.__get__.return_value = {}
self.assertEqual(len(Base().assignment.values()), 0)
# ... and so on
Run Code Online (Sandbox Code Playgroud)
您可以在http://www.voidspace.org.uk/python/mock/patch.html#mock.patch找到更多详细信息.
如果您的类(例如,队列)已经在测试中导入 -并且您想要修补MAX_RETRY attr-您可以使用@ patch.object或更好的@ patch.multiple
from mock import patch, PropertyMock, Mock
from somewhere import Queue
@patch.multiple(Queue, MAX_RETRY=1, some_class_method=Mock)
def test_something(self):
do_something()
@patch.object(Queue, 'MAX_RETRY', return_value=1, new_callable=PropertyMock)
def test_something(self, _mocked):
do_something()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
27044 次 |
| 最近记录: |