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

如何用Pytest测试含参数Discord Bot的on_command_error异常消息发送

问题:测试带参数Discord命令的错误处理逻辑失败

我在编写Pytest单元测试,验证Discord Bot的错误处理逻辑:当调用带必填参数的命令且未加载游戏时,触发CommandInvokeError后,on_command_error()需要发送「Game not loaded....」提示消息。

无参数命令的测试用invoke(ctx)能正常通过,但带参数的log命令尝试用invoke(ctx, words=10)时会触发TypeError;尝试直接调用命令方法、使用callback或手动dispatch事件,都无法通过断言——Bot实际运行正常,但测试始终失败。

问题分析

  1. invoke()方法参数错误:Discord.py的Command.invoke()方法不支持直接传入命令参数(比如words=10),它依赖解析ctx.message.content来获取参数,直接传参会触发类型错误。
  2. 错误链不匹配:on_command_error()的判断条件要求err.__cause__是AttributeError且self.game为None,若测试中触发的错误不符合这个链,断言就会失败。

解决方案

方法一:模拟命令消息,让Discord.py自动解析参数

通过设置ctx.message.content模拟用户发送的命令消息,让invoke()方法正常解析参数,触发预期的错误链:

@pytest.mark.asyncio
async def test_submit_words_no_game(
    bot: client.WordDebtBot, player: game_lib.WordDebtPlayer
):
    ctx = AsyncMock()
    ctx.author.id = player.user_id
    # 模拟用户发送的命令消息,包含前缀和参数
    ctx.message.content = "!log 10"
    ctx.prefix = "!"

    game_cmds_cog = bot.get_cog("Core Gameplay Module")
    cmd_err_cog = bot.get_cog("Command Error Handler")
    game_cmds_cog.game = None
    cmd_err_cog.game = None

    with pytest.raises(commands.CommandInvokeError) as err_info:
        await game_cmds_cog.log.invoke(ctx)

    # 调用错误处理方法
    await cmd_err_cog.on_command_error(ctx, err_info.value)

    # 断言消息发送正确
    ctx.send.assert_called_with("Game not loaded....")

方法二:直接调用命令callback,手动构造错误对象

如果不想依赖命令解析逻辑,可以直接调用命令的callback方法,捕获AttributeError后,手动封装成CommandInvokeError传给错误处理器:

@pytest.mark.asyncio
async def test_submit_words_no_game(
    bot: client.WordDebtBot, player: game_lib.WordDebtPlayer
):
    ctx = AsyncMock()
    ctx.author.id = player.user_id

    game_cmds_cog = bot.get_cog("Core Gameplay Module")
    cmd_err_cog = bot.get_cog("Command Error Handler")
    game_cmds_cog.game = None
    cmd_err_cog.game = None

    try:
        # 直接调用命令的callback方法,触发AttributeError
        await game_cmds_cog.log.callback(game_cmds_cog, ctx, words=10)
    except AttributeError as attr_err:
        # 封装成符合要求的CommandInvokeError
        invoke_err = commands.CommandInvokeError(attr_err)
        # 调用错误处理逻辑
        await cmd_err_cog.on_command_error(ctx, invoke_err)

    # 断言消息发送正确
    ctx.send.assert_called_with("Game not loaded....")

关键说明

  • 方法一更贴近真实用户场景,测试命令解析和错误处理的完整流程
  • 方法二更聚焦错误处理逻辑本身,跳过命令解析环节,适合单独验证错误处理器的判断逻辑

内容的提问来源于stack exchange,提问作者Gregory Nitch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 17:43:15