You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为包含嵌套方法的Twisted addCallback逻辑编写单元测试

Twisted 异步逻辑单元测试方案

核心依赖工具

  • 使用Twisted原生测试框架 twisted.trial.unittest.TestCase 作为测试基类,原生支持Deferred异步用例
  • 使用 twisted.internet.task.Clock 模拟reactor时间,无需真实等待即可验证重试逻辑
  • Mock method3 返回值,覆盖所有回调分支

完整测试代码示例

首先给出与你提供的逻辑对齐的被测类示意:

from twisted.internet.defer import Deferred

class MyService:
    def __init__(self, reactor):
        self.reactor = reactor
        self.state = None

    def method1(self):
        self.method2()

    def method2(self):
        def method2_success(result):
            if result.code == 200:
                self.state = 'running'
            else:
                self.state = 'failed'
                self.reactor.callLater(10, self.method2)

        def method2_failed(failure):
            self.state = 'failed'
            self.reactor.callLater(10, self.method2)

        self.state = 'in_progress'
        d = self.method3()
        d.addCallbacks(method2_success, method2_failed)
        return d

    def method3(self):
        return some_deffered_object

测试类实现:

from twisted.trial import unittest
from twisted.internet.task import Clock
from twisted.internet.defer import Deferred, fail

# 模拟method3返回的带code属性的结果对象
class MockResult:
    def __init__(self, code):
        self.code = code

class TestMyService(unittest.TestCase):
    def setUp(self):
        # 初始化模拟时钟和被测实例
        self.clock = Clock()
        self.service = MyService(reactor=self.clock)

    def test_method2_success_with_200(self):
        """测试method3返回200成功的场景"""
        # Mock method3返回200成功结果
        mock_res = MockResult(code=200)
        self.service.method3 = lambda: Deferred.callback(mock_res)

        d = self.service.method2()
        # Deferred执行完成后做断言
        def assert_result(_):
            self.assertEqual(self.service.state, 'running')
            # 验证无重试调度生成
            self.assertEqual(len(self.clock.calls), 0)
        d.addCallback(assert_result)
        return d

    def test_method2_success_with_non_200(self):
        """测试method3返回非200状态的场景"""
        mock_res = MockResult(code=400)
        self.service.method3 = lambda: Deferred.callback(mock_res)

        d = self.service.method2()
        def assert_result(_):
            self.assertEqual(self.service.state, 'failed')
            # 验证10秒后重试的调度已正确注册
            self.assertEqual(len(self.clock.calls), 1)
            self.assertEqual(self.clock.calls[0].delay, 10)
            self.assertEqual(self.clock.calls[0].func, self.service.method2)
        d.addCallback(assert_result)
        return d

    def test_method2_failure(self):
        """测试method3调用失败的场景"""
        # Mock method3返回失败结果
        self.service.method3 = lambda: fail(Exception("call failed"))

        d = self.service.method2()
        def assert_result(_):
            self.assertEqual(self.service.state, 'failed')
            # 验证重试调度正常生成
            self.assertEqual(len(self.clock.calls), 1)
            self.assertEqual(self.clock.calls[0].delay, 10)
        # 用addBoth处理失败态的Deferred,避免测试直接报错
        d.addBoth(assert_result)
        return d

    def test_method1_call(self):
        """测试method1正确触发method2调用"""
        call_count = 0
        def mock_method2():
            nonlocal call_count
            call_count +=1
            return Deferred.callback(None)
        self.service.method2 = mock_method2

        self.service.method1()
        self.assertEqual(call_count, 1)

测试运行方式

直接执行命令 trial 测试文件名.py 即可,Twisted trial会自动处理异步Deferred的等待、异常捕获和断言校验。

内容的提问来源于stack exchange,提问作者Mahendra Garg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 05:09:03