how to test actioncable
Table of Contents

    截至我打下这行字的时候(2016-06-26) 时,rails 并没有自带的 helper 来帮助我们测试 actioncable。对比着我们可以看看 activejob 的 test helper,我说的 helper 大概就是这个意思。

    但是我们还是要测试啊,于是只能自己开动脑筋啦。首先我们在你的项目的文件夹下运行一下命令,找到 actioncable 的位置:

    $ bundle show actioncable
    

    然后在该文件夹下找到 lib/action_cable/subscription_adapter/base.rb 文件,这个就是 adapter 的基类,实现这些接口 你就可以造自己的 adapter。这个其实和 activejob 很像,你可以选择不同的 queue backend,因为 rails 设定了一层薄薄的 抽象层,所以只要你按照规矩来实现一个符合接口的,你都是可以用的。那我们这里要搞什么呢,没错,我们要自己搞个大新闻, 实现一个简单地 broadcast adapter,然后通过插入或修改来达到我们测试的目的。

    那么问题来了,假设我们十分顺利地实现了,怎么让 rails 知道我们在某个地方放着这样的一个我们实现的 adapter 呢?这个 秘密在于 require。

    我们接着在之前的文件夹下,找到 lib/action_cable/server/configuration.rb 中的 pubsub_adapter 函数:

    def pubsub_adapter
       adapter = (cable.fetch('adapter') { 'redis' })
       path_to_adapter = "action_cable/subscription_adapter/#{adapter}"
       begin
         require path_to_adapter
         ...
    

    adapter 的设置在 config/cable.yml 中,然后 rails 找到你指定的 adapter,拼接出路径,然后 require 它。你打开 action_cable/subscription_adapter/ 文件下,就会发现下面的已经实现的 adapter。那么问题来了,难道我们要把自己 实现的 adapter 也放到这个目录下面么?

    不是的。require 是有优先级之分的。它会先找某个路径,接着是另一个,然后依次尝试。在你项目的文件夹下打开 rails console, 运行以下命令:

    $:

    你可以看到一个包含了很多路径的 array。它就是 require 会找的地方。可以发现第一个是你项目目录下的 lib 目录。讲到这里 是不是有些想法了呢?我们可以在 lib 目录下建立 action_cable/subscription_adapter/my_adapter.rb 这样的目录结构, 然后在配置文件中(config/cable.yaml) 中的 test 的 adapter 指定为我们自己的 adapter。然后照着官方实现的 adapter, 自己实现接口,并加入需要的东西来测试,这样就可以了。

    额,可能最后的部分讲的有些粗糙,但是不用担心,原因后续说明。之前我这里的需求场景是测试有没有广播,广播的内容是否正确。 然后我继承 inline adapter 覆盖了 broadcast 方法来获得广播内容。但是好像不是很优雅啊。好消息是,已经有个好心人实现了 helper,并提了 pr, 预计会在 5.0.1 版本发布。所以呢,你其实不用自己实现 adapter 了。我把他实现的 test adapter 放在之前说的 lib 目录下,然后把它实现的 help 放到测试的 test_helper.rb, 然后就过上了幸福的生活!