在python单元测试中模拟类属性的更好方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22324628/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Better way to mock class attribute in python unit test
提问by Ivo van der Wijk
I have a base class that defines a class attribute and some child classes that depend on it, e.g.
我有一个定义类属性的基类和一些依赖它的子类,例如
class Base(object):
assignment = dict(a=1, b=2, c=3)
I want to unittest this class with different assignments, e.g. empty dictionary, single item, etc. This is extremely simplified of course, it's not a matter of refactoring my classes or tests
我想用不同的作业对这个类进行单元测试,例如空字典、单个项目等。这当然是非常简化的,这不是重构我的类或测试的问题
The (pytest) tests I have come up with, eventually, that work are
我提出的(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
This feels rather complicated and hacky - I don't even fully understand why it works (I am familiar with descriptors though). Does mock automagically transform class attributes into descriptors?
这感觉相当复杂和 hacky - 我什至不完全理解它为什么起作用(虽然我熟悉描述符)。mock 会自动将类属性转换为描述符吗?
A solution that would feel more logical does not work:
感觉更合乎逻辑的解决方案不起作用:
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
or just
要不就
def test_single(self):
with mock.patch("base.Base") as a:
a.assignment = {'a':1}
assert len(Base().assignment.values()) == 1
Other variants that I've tried don't work either (assignments remains unchanged in the test).
我尝试过的其他变体也不起作用(测试中的分配保持不变)。
What's the proper way to mock a class attribute? Is there a better / more understandable way than the one above?
模拟类属性的正确方法是什么?有没有比上面更好/更容易理解的方法?
采纳答案by Martijn Pieters
base.Base.assignmentis simply replaced with a Mockobject. You madeit a descriptor by adding a __get__method.
base.Base.assignment简单地替换为一个Mock对象。您提出通过添加它描述__get__方法。
It's a little verbose and a little unnecessary; you could simply set base.Base.assignmentdirectly:
它有点冗长,有点不必要;你可以简单地base.Base.assignment直接设置:
def test_empty(self):
Base.assignment = {}
assert len(Base().assignment.values()) == 0
This isn't too safe when using test concurrency, of course.
当然,这在使用测试并发时不太安全。
To use a PropertyMock, I'd use:
要使用 a PropertyMock,我会使用:
with patch('base.Base.assignment', new_callable=PropertyMock) as a:
a.return_value = {'a': 1}
or even:
甚至:
with patch('base.Base.assignment', new_callable=PropertyMock,
return_value={'a': 1}):
回答by Dan Keder
To improve readability you can use the @patchdecorator:
为了提高可读性,您可以使用@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
You can find more details at http://www.voidspace.org.uk/python/mock/patch.html#mock.patch.
您可以在http://www.voidspace.org.uk/python/mock/patch.html#mock.patch找到更多详细信息。
回答by pymen
If your class (Queue for example) in already importedinside your test - and you want to patch MAX_RETRYattr - you can use @patch.objector simply better @patch.multiple
如果您的类(例如队列)已经在您的测试中导入- 并且您想要修补MAX_RETRYattr - 您可以使用@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()
回答by x0s
Here is an example how to unit-test your Baseclass:
以下是如何对Base类进行单元测试的示例:
- mocking multiple class attributesof different types (ie:
dictandint) - using the
@patchdecorator andpytestframework with withpython 2.7+or3+.
- 模拟不同类型的多个类属性(即:
dict和int) - 使用带有或的
@patch装饰器和pytest框架。python 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)
回答by igniteflow
Perhaps I'm missing something, but isn't this possible without using PropertyMock?
也许我遗漏了一些东西,但是如果不使用,PropertyMock难道这不可能吗?
with mock.patch.object(Base, 'assignment', {'bucket': 'head'}):
# do stuff

