如何使用 Twisted Trial 对 Autobahn 应用程序进行单元测试?

How to do unit test on Autobahn applications using Twisted Trial?

假设您仅使用 Autobahn 连接(而非原始 WebSocket)。

我们如何测试 WITHOUT 网络、我们的 RPC 方法和事件?
由于它是 Twisted,我认为最合适的工具是 Twisted Trial。

但我不知道应该如何编写这些测试,而不编写大量样板代码并重新使用 Autobahn 的内部实现(甚至我不确定我是否能够做到)这样)。

你会怎么做?

试图回答我自己的问题。

问题

然后,要对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) 或类似的东西来解决。