Ответ 1
Смотрите: 26.5.3.4. Применение одного и того же патча к каждому методу тестирования
Это имеет смысл настроить патчер таким образом на setUp, если вы хотите, чтобы исправление было выполнено для всех методов тестирования.
В моей попытке изучить TDD, пытаясь изучить модульное тестирование и использовать mock с python. Постепенно выискивайте его, но не уверены, правильно ли я это делаю. Предупреждаем: я использую python 2.4, потому что API-интерфейс поставщика поставляется в виде предварительно скомпилированных файлов 2.4 pyc, поэтому я использую mock 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
Теперь в моем тестовом файле "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
Отвечает мне на пару вопросов:
Спасибо.
Смотрите: 26.5.3.4. Применение одного и того же патча к каждому методу тестирования
Это имеет смысл настроить патчер таким образом на setUp, если вы хотите, чтобы исправление было выполнено для всех методов тестирования.
Если у вас много патчей для применения, и вы хотите, чтобы они применялись к вещам, инициализированным в методах 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.stop_all()
Начну с ответа на ваши вопросы, а затем дам подробный пример взаимодействия 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)