RapidSMS 测试完整指南:脚本化测试与测试工具链从零实战

【免费下载链接】rapidsms Build SMS applications with Python 【免费下载链接】rapidsms 项目地址: https://gitcode.com/gh_mirrors/ra/rapidsms

RapidSMS 是一个用 Python 构建短信应用的开源框架,而 RapidSMS 测试 则是保证消息路由、应用处理逻辑稳定可靠的关键一环。本文面向新手,完整介绍 RapidSMS 的脚本化测试(Scripted Testing)与内置测试工具链(Test Harness),从环境准备、编写第一个测试用例到运行整个测试套件,带你从零实战、快速上手。

RapidSMS 测试架构图:消息从后端经路由器五阶段处理进入 Django 应用

如上图所示,SMS 消息从 GSM Modem、Kannel、HTTP 等后端进入,经过消息队列与 Router 的 Filter → Parse → Handle → Default → Cleanup 五个阶段,最终交给 Django 应用处理。RapidSMS 测试正是围绕这条完整链路展开的。

为什么要给 RapidSMS 应用写自动化测试

短信应用一旦上线,消息解析、多应用协作、数据库状态等问题都可能悄悄出现。自动化测试能反复验证你的代码是否按预期工作,确保新增功能不会破坏已有逻辑。官方文档 docs/topics/testing.rst 建议为所有 RapidSMS 应用编写测试,重点覆盖三个方面:

  • 消息解析:应用如何区分 qq ocean blue?会不会被多余空格或相似单词干扰?
  • 工作流:当数据库中没有题目、没有联系人时,应用会如何响应?
  • 业务逻辑:答案判断、关键词匹配是否正确?

测试前的准备工作:环境与依赖

RapidSMS 测试基于标准的 Python unittest 与 Django 测试体系,你不需要额外学习新的测试框架。准备步骤如下:

  1. 克隆项目:git clone https://gitcode.com/gh_mirrors/ra/rapidsms
  2. 安装开发依赖,参考 tests/requirements/dev.txt
  3. 配置 Django settings 与测试数据库(项目内置 tests/default.pytests/urls.py 可直接参考)

RapidSMS 测试工具链全景:五大核心组件

RapidSMS 在 rapidsms/tests/harness/ 下提供了一套开箱即用的测试工具链,核心组件包括:

组件 作用
RapidTest / RapidTransactionTest 通用测试基类,自动装配 TestRouter,可检查收发消息
TestScript / TestScriptMixin 脚本化测试框架,用对话式脚本编写集成测试
TestRouter 记录所有入站/出站消息的路由器,供测试断言
CreateDataMixin / LoginMixin 快速创建联系人、连接、消息等测试数据的辅助工具
MockBackend / EchoApp 模拟后端与应用,隔离真实短信通道

其中 RapidTestTestScript 等类在 rapidsms/tests/harness/init.py 中定义,TestRouterrapidsms/router/test/router.py 中实现。

使用 RapidTest 编写第一个测试用例

RapidTest 提供了最简单的测试环境:通过 receive 模拟收到短信,通过 outbound 属性检查应用回复的内容。以官方文档中的问答应用为例:

from rapidsms.tests.harness import RapidTest

class QuizMeStackTest(RapidTest):

    def test_no_questions(self):
        """数据库为空时,应回复提示信息"""
        self.receive('q', self.lookup_connections('1112223333')[0])
        self.assertEqual(self.outbound[0].text, 'No questions exist.')

短短几行代码,就完成了「短信进入 → 经过整个路由栈 → 应用响应」的全流程验证。lookup_connections 会自动创建 Connection 对象,无需手动准备数据。

检查数据库状态:更细粒度的断言

如果你的应用会写入数据库,可以用 RapidTest 结合 ORM 断言,检查测试后的数据状态:

msg = self.receive('q ocean blue', self.lookup_connections('1112223333')[0])
self.assertEqual(self.outbound[0].text, 'Correct!')
answer = Answer.objects.all()[0]
self.assertTrue(answer.correct)
self.assertEqual(msg.connection, answer.connection)

脚本化测试入门:像写剧本一样写测试

RapidSMS 的脚本化测试(Scripted Testing)是官方推荐的高层集成测试方式:把「用户发什么、系统回什么」写成一段对话脚本,交给框架自动执行和断言。脚本语法非常简单:

  • 号码 > 短信内容:表示该号码发来一条入站消息
  • 号码 < 短信内容:表示系统向该号码回复一条出站消息

例如问答应用的完整对话可以写成:

1112223333 > q
1112223333 < What color is the ocean? Answer with 'q ocean <answer>'
1112223333 > q ocean blue
1112223333 < Correct!

在测试类中通过 runScript 执行这段脚本即可:

from rapidsms.tests.harness import TestScript
from quizme.app import QuizMeApp

class QuizMeScriptTest(TestScript):
    apps = (QuizMeApp,)

    def test_correct_script(self):
        self.runScript("""
            1112223333 > q
            1112223333 < What color is the ocean? Answer with 'q ocean <answer>'
            1112223333 > q ocean blue
            1112223333 < Correct!
        """)

注意 apps 必须在类级别定义,它告诉测试框架路由器要加载哪些应用。脚本解析与执行的完整逻辑位于 rapidsms/tests/harness/scripted.py,其中 parseScript 负责解析脚本,runParsedScript 负责按顺序执行并逐条比对消息。

脚本化测试进阶:日期、注释与顺序匹配

parseScript 还支持两个实用特性:

  • 注释行:以 # 开头的行会被忽略,方便为脚本添加说明
  • 时间戳:在号码后附加 @年月日时分(如 19232922@200804150730),可模拟指定时间到达的消息

脚本执行时按顺序处理:遇到 > 就发送入站消息,遇到 < 就从出站消息中查找匹配的回复。如果一条入站消息触发了多条回复,框架会逐一比对,直到找到匹配项——这保证了对话顺序的严谨性。

测试应用逻辑:脱离路由的快速单元测试

对于不依赖消息路由的纯业务逻辑,可以跳过整套路由架构,直接构造应用对象进行测试,执行速度更快:

from django.test import TestCase
from rapidsms.router.test import TestRouter
from quizme.app import QuizMeApp

class QuizMeLogicTest(TestCase):

    def setUp(self):
        self.app = QuizMeApp(TestRouter())

    def test_inquiry_whitespace(self):
        self.assertTrue(self.app.is_quiz(" q "))

如果只关心「消息是否到达路由器」,而不关心应用处理逻辑,还可以给 TestRouter 传入 disable_phases=True 跳过路由阶段,见 rapidsms/tests/harness/router.py

常用测试辅助工具速查

  • CreateDataMixin:提供 create_contact()create_connection()create_incoming_message()random_string() 等方法,一键生成测试数据,源码见 rapidsms/tests/harness/base.py
  • CustomRouterMixin:通过类属性 router_classbackends 覆盖路由器与后端配置,用于测试自定义路由
  • DatabaseBackendMixin:使用真实的 DatabaseBackend,并通过 sent_messages 检查已发送消息
  • MockBackend:把发送的消息存进内存列表,clear() 可清空收件箱,见 rapidsms/tests/harness/backend.py
  • LoginMixin:自动创建用户并登录,方便测试需要鉴权的 Web 视图

运行测试:run_tests.py 与 Django Test Runner

项目根目录的 run_tests.py 封装了 Django 测试运行器,用法如下:

python run_tests.py rapidsms            # 运行整个框架的测试
python run_tests.py rapidsms.tests.test_scripted   # 运行指定测试模块
python run_tests.py -v 2 --noinput      # 详细输出、跳过交互提示

也可以直接用 Django 的方式运行:

python -m django test rapidsms --settings=tests.default

框架自带大量可直接借鉴的测试用例,例如 rapidsms/tests/test_scripted.pyrapidsms/tests/test_app_base.pyrapidsms/backends/test_base.py 以及 contrib 各应用的 tests 目录(如 rapidsms/contrib/messagelog/tests/)。

扩展:测试 Celery 异步任务与定时任务

如果项目使用 Celery 路由器(见 rapidsms/router/celery/),消息处理会异步化。这类场景下,除了断言消息本身,还要关注定时任务的配置与执行结果:

RapidSMS 测试中 Celery 定时任务配置示例

如上图所示,周期任务在 Django 管理后台中配置(名称、启用开关、Interval/Crontab 调度策略)。测试时应验证任务已正确注册、调度参数符合预期,并结合 Celery 的测试工具(如 celery.contrib.testing)模拟任务执行。

测试最佳实践与常见陷阱

  • 从最小单元开始:先测试纯函数(如 check_answer),再逐层往上,失败时更容易定位问题
  • 优先使用脚本化测试做集成验证:跨多个应用的消息流转用 TestScript 最直观,但需要检查脚本中途的数据库状态时,改用 RapidTest 更灵活
  • 保持收件箱干净TestScript.runScript 会自动清空出站消息;手动测试时可用 clear_sent_messages() 清理
  • 警惕旧 API:老版本 rapidsms/tests/scripted.py 中的 startRouter/stopRouter 已标记为弃用,请使用新的 rapidsms.tests.harness 接口

结语

RapidSMS 测试并不神秘:RapidTest 帮你快速验证单条消息的处理,TestScript 让你用对话剧本完成端到端集成测试,再配合 CreateDataMixinMockBackend 等工具,一套完整的测试体系很快就能搭建起来。希望这份 RapidSMS 测试完整指南能帮你写出稳定、可维护的短信应用,让每一次发布都更有底气。

【免费下载链接】rapidsms Build SMS applications with Python 【免费下载链接】rapidsms 项目地址: https://gitcode.com/gh_mirrors/ra/rapidsms

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐