Как выполнить модульное тестирование приложений Autobahn с использованием Twisted Trial?
Предполагая, что вы используете только соединение Autobahn (не сырой WebSocket).
Как мы можем протестировать БЕЗ сети, наши методы и события RPC?
Поскольку это Twisted, я думаю, что наиболее подходящим инструментом будет Twisted Trial.
Но я не могу понять, как мне писать эти тесты, без написания большого количества стандартного кода и повторного использования внутренней реализации Autobahn (и даже я не уверен, что смогу сделать это таким образом).
Как бы вы это сделали?
1 ответ
Это попытка ответить на мой собственный вопрос.
Эта проблема
Затем, чтобы выполнить модульное тестирование методов и событий RPC, мы должны предположить, что Autobahn хорошо протестирован, и нам не нужно его тестировать, решение становится простым:
Решение
Дразнить всех.
контекст
В моем приложении у меня есть два типа компонентов (читай ApplicationSession): StandardComponent и DatabaseComponent (который наследуется от StandardComponent).
Самая большая проблема во время модульного тестирования заключается в том, что у нас много зависимостей, таких как соединение с базой данных, соединение Redis и т. Д...
Примеры
Что я делаю в своих тестах, так это исправляю все эти объекты с помощью подклассов unittest.TestCase
:
class APITestCase(unittest.TestCase):
def _patchObject(self, module_name, **kwargs):
patcher = patch(module_name, **kwargs)
mock = patcher.start()
self.patches.append(patcher)
return mock
def setUp(self):
logging.disable(logging.CRITICAL)
self.patches = []
self.session = self._patchObject('components.ApplicationAPI')
self.database = self._patchObject('txpostgres.txpostgres.Connection')
def tearDown(self):
for patcher in self.patches:
patcher.stop()
В моем тестовом примере я внедряю ложную сессию и проверенную базу данных.
Затем тестирование становится очень очень простым.
Всякий раз, когда я вызываю метод RPC, который должен вызвать базу данных или получить результаты из базы данных, я исправляю его: self.mocked_auth_user.return_value = (1, "abc", "something", "admin")
И в моем методе испытаний:
def test_authenticate_success(self):
self.mocked_auth_user.return_value = (1, "abc", "paris", "admin")
def _doTest(auth_result):
attempted_auth_result = {
"secret": "abc",
"role": "admin",
"authid": "1",
"salt": "paris",
"iterations": 1000,
"keylen": 32
}
self.assertEqual(auth_result, attempted_auth_result)
self.mocked_auth_user.assert_called_with(self.api.database, "raito")
return self.api.authenticate("test", "raito", {}).addCallback(_doTest)
Вы можете сделать несколько более сложных и интересных тестов, чтобы убедиться, что ваш метод надежен:
def test_authenticate_authid_not_found(self):
def _raiseException(db, user):
return defer.fail(Exception("User {} not found!".format(user)))
self.mocked_auth_user.side_effect = _raiseException
return self.failUnlessFailure(self.api.authenticate("test", "raito", {}), AuthenticationError)
То же самое касается событий, вам просто нужно вызвать их и проверить, публикуют ли они событие или нет (self.session.publish.assert_called_with(...)
)
Это становится волшебством!
В любом случае, это решает проблему модульного тестирования, но интеграция еще не завершена. Я работаю над этим, но проблема, вероятно, будет решена с помощью некоторой технологии виртуализации (Docker) или чего-то в этом роде.