問題描述
在我嘗試學習 TDD 的過程中,嘗試學習單元測試并在 python 中使用 mock.慢慢掌握它,但不確定我是否正確執行此操作.預先警告:我堅持使用 python 2.4,因為供應商 API 是作為預編譯的 2.4 pyc 文件提供的,所以我使用的是 mock 0.8.0 和 unittest(不是 unittest2)
In my attempt to learn TDD, trying to learn unit testing and using mock with python. Slowly getting the hang of it, but unsure if I'm doing this correctly. Forewarned: I'm stucking using python 2.4 because the vendor API's come as pre-compiled 2.4 pyc files, so I'm using mock 0.8.0 and unittest ( not unittest2 )
鑒于 'mymodule.py' 中的示例代碼
Given this example code in '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
現在在我的測試用例文件test_myclass.py"中,我想模擬 ldap 對象.ldap.initialize 返回 ldap.ldapobject.SimpleLDAPObject,所以我認為這是我必須模擬出來的方法.
Now in my test case file 'test_myclass.py', I want to mock the ldap object out. ldap.initialize returns the ldap.ldapobject.SimpleLDAPObject, so I figured that'd be the method I'd have to mock out.
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
讓我想到幾個問題:
- 看起來對嗎?:)
- 這是嘗試模擬在我正在測試的類中實例化的對象的正確方法嗎?
- 是否可以在 setUp 上調用 @patch 裝飾器,否則會導致奇怪的副作用?
- 有沒有辦法模擬引發 ldap.INVALID_CREDENTIALS 異常而不必將異常導入我的測試用例文件?
- 我應該改用 patch.object() 嗎?如果可以,該怎么做?
謝謝.
推薦答案
你可以使用patch()
作為類裝飾器,而不僅僅是作為函數裝飾器.然后你可以像以前一樣傳入模擬函數:
You can use patch()
as a class decorator, not just as a function decorator. You can then pass in the mocked function as before:
@patch('mymodule.SomeClass')
class MyTest(TestCase):
def test_one(self, MockSomeClass):
self.assertIs(mymodule.SomeClass, MockSomeClass)
參見:對每個測試方法應用相同的補丁(其中還列出了替代方法)
See: Applying the same patch to every test method (which also lists alternatives)
如果您希望對所有測試方法進行修補,那么在 setUp 上以這種方式設置修補程序更有意義.
It makes more sense to set up the patcher this way on setUp if you want the patching to be done for all the test methods.
這篇關于如何通過 unittest setUp 在 python 中正確使用 mock的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!