Как выполнить модульное тестирование приложений 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) или чего-то в этом роде.

Другие вопросы по тегам