sjm*_*jmh 56 python unit-testing mocking
在我尝试学习TDD时,尝试学习单元测试并使用mock与python.慢慢地掌握它,但不确定我是否正确地这样做.预警:我正在坚持使用python 2.4,因为供应商API是预先编译的2.4 pyc文件,所以我使用模拟0.8.0和unittest(不是unittest2)
给出'mymodule.py'中的示例代码
import ldap
class MyCustomException(Exception):
pass
class MyClass:
def __init__(self, server, user, passwd):
self.ldap = ldap.initialize(server)
self.user = user
self.passwd = passwd
def connect(self):
try:
self.ldap.simple_bind_s(self.user, self.passwd)
except ldap.INVALID_CREDENTIALS:
# do some stuff
raise MyCustomException
Run Code Online (Sandbox Code Playgroud)
现在在我的测试用例文件'test_myclass.py'中,我想模拟ldap对象.ldap.initialize返回ldap.ldapobject.SimpleLDAPObject,所以我认为这是我必须嘲笑的方法.
import unittest
from ldap import INVALID_CREDENTIALS
from mock import patch, MagicMock
from mymodule import MyClass
class LDAPConnTests(unittest.TestCase):
@patch('ldap.initialize')
def setUp(self, mock_obj):
self.ldapserver = MyClass('myserver','myuser','mypass')
self.mocked_inst = mock_obj.return_value
def testRaisesMyCustomException(self):
self.mocked_inst.simple_bind_s = MagicMock()
# set our side effect to the ldap exception to raise
self.mocked_inst.simple_bind_s.side_effect = INVALID_CREDENTIALS
self.assertRaises(mymodule.MyCustomException, self.ldapserver.connect)
def testMyNextTestCase(self):
# blah blah
Run Code Online (Sandbox Code Playgroud)
引出了几个问题:
谢谢.
joo*_*oks 61
您可以将其patch()用作类装饰器,而不仅仅是作为函数装饰器.然后,您可以像以前一样传入模拟函数:
@patch('mymodule.SomeClass')
class MyTest(TestCase):
def test_one(self, MockSomeClass):
self.assertIs(mymodule.SomeClass, MockSomeClass)
Run Code Online (Sandbox Code Playgroud)
见:26.5.3.4.将相同的补丁应用于每个测试方法(也列出替代方案)
如果您希望对所有测试方法进行修补,那么在setUp上以这种方式设置修补程序更有意义.
Don*_*kby 12
我将首先回答您的问题,然后我将详细介绍如何patch()和setUp()互动.
@patch()装饰器setUp().你很幸运,因为setUp()在测试方法中创建了对象并且永远不会创建对象.patch.object()这里.它只是允许您修补对象的属性,而不是将目标指定为字符串.为了扩展我对问题#3的回答,问题是patch()装饰器仅在装饰函数运行时应用.一旦setUp()返回,该补丁被删除.在你的情况下,这是有效的,但我敢打赌,这会让看到这个测试的人感到困惑.如果你真的只想要在这期间发生补丁setUp(),我会建议使用该with语句来明确补丁将被删除.
以下示例有两个测试用例.TestPatchAsDecorator表明装饰类将在测试方法期间应用补丁,但不会在期间setUp().TestPatchInSetUp显示了如何应用补丁以使其在setUp()测试方法和测试方法中都适用.调用self.addCleanUp()确保在此期间删除补丁tearDown().
import unittest
from mock import patch
@patch('__builtin__.sum', return_value=99)
class TestPatchAsDecorator(unittest.TestCase):
def setUp(self):
s = sum([1, 2, 3])
self.assertEqual(6, s)
def test_sum(self, mock_sum):
s1 = sum([1, 2, 3])
mock_sum.return_value = 42
s2 = sum([1, 2, 3])
self.assertEqual(99, s1)
self.assertEqual(42, s2)
class TestPatchInSetUp(unittest.TestCase):
def setUp(self):
patcher = patch('__builtin__.sum', return_value=99)
self.mock_sum = patcher.start()
self.addCleanup(patcher.stop)
s = sum([1, 2, 3])
self.assertEqual(99, s)
def test_sum(self):
s1 = sum([1, 2, 3])
self.mock_sum.return_value = 42
s2 = sum([1, 2, 3])
self.assertEqual(99, s1)
self.assertEqual(42, s2)
Run Code Online (Sandbox Code Playgroud)
Dan*_*ple 10
如果要应用许多补丁并且希望它们应用于setUp方法中初始化的内容,请尝试以下操作:
def setUp(self):
self.patches = {
"sut.BaseTestRunner._acquire_slot": mock.Mock(),
"sut.GetResource": mock.Mock(spec=GetResource),
"sut.models": mock.Mock(spec=models),
"sut.DbApi": make_db_api_mock()
}
self.applied_patches = [mock.patch(patch, data) for patch, data in self.patches.items()]
[patch.apply for patch in self.applied_patches]
.
. rest of setup
.
def tearDown(self):
patch.stopall()
Run Code Online (Sandbox Code Playgroud)
我想指出一种可接受的答案的变体,其中将一个new参数传递给patch()装饰器:
from unittest.mock import patch, Mock
MockSomeClass = Mock()
@patch('mymodule.SomeClass', new=MockSomeClass)
class MyTest(TestCase):
def test_one(self):
# Do your test here
Run Code Online (Sandbox Code Playgroud)
请注意,在这种情况下,不再需要MockSomeClass向每个测试方法中添加第二个参数,这可以节省大量代码重复。
对此的说明可以在https://docs.python.org/3/library/unittest.mock.html#patch中找到:
如果将if
patch()用作装饰器,并且省略new,则将创建的模拟作为额外的参数传递给装饰函数。
首先,答案省略new,但是将其包括在内可能很方便。
| 归档时间: |
|
| 查看次数: |
40292 次 |
| 最近记录: |