4 个版本

0.1.3 2024年8月1日
0.1.2 2024年7月30日
0.1.1 2024年7月29日
0.1.0 2024年7月17日

#123测试

Download history 62/week @ 2024-07-11 47/week @ 2024-07-18 213/week @ 2024-07-25 161/week @ 2024-08-01 1/week @ 2024-08-08

484 每月下载量

MIT 许可证

250KB
5.5K SLoC

teloxide tests

一个允许你轻松进行 teloxide 机器人单元测试的 Crate!无需互联网、账户或任何东西!

这个 Crate 有什么

  • 易于测试具有对原始机器人请求的访问权限的处理程序(请参阅 hello_world_bot
  • 支持依赖项,更改 me 和多次更新(请参阅 album_bot
  • 语法糖和本地支持存储、对话和状态(请参阅 calculator_bot
  • 模拟文件获取和下载(请参阅 file_download_bot
  • 支持与数据库一起使用(请参阅 phrase_bot

示例

简化版 [hello_world_bot](https://github.com/LasterAlex/teloxide_tests/blob/master/examples/hello_world_bot/src/main.rs)

#[tokio::test]
async fn test_hello_world() {
    let message = MockMessageText::new().text("Hi!");
    let bot = MockBot::new(message, handler_tree());
    // Sends the message as if it was from a user
    bot.dispatch().await;  

    let responses = bot.get_responses();
    let message = responses
        .sent_messages
        .last()
        .expect("No sent messages were detected!");
    assert_eq!(message.text(), Some("Hello World!"));
}

[file_download_bot](https://github.com/LasterAlex/teloxide_tests/blob/master/examples/file_download_bot/src/main.rs)

#[tokio::test]
async fn test_not_a_document() {
    let bot = MockBot::new(MockMessageText::new().text("Hi!"), handler_tree());
    // Syntactic sugar
    bot.dispatch_and_check_last_text("Not a document").await;
}

#[tokio::test]
async fn test_download_document_and_check() {
    let bot = MockBot::new(MockMessageDocument::new(), handler_tree());
    bot.dispatch_and_check_last_text("Downloaded!").await;
}

[calculator_bot](https://github.com/LasterAlex/teloxide_tests/blob/master/examples/calculator_bot/src/tests.rs)

#[tokio::test]
async fn test_what_is_the_first_number() {
    let bot = MockBot::new(MockCallbackQuery::new().data("add"), handler_tree());

    bot.dependencies(deps![get_bot_storage().await]);
    bot.set_state(State::WhatDoYouWant).await;

    bot.dispatch_and_check_last_text_and_state(
        text::ENTER_THE_FIRST_NUMBER,
        State::GetFirstNumber {
            operation: "add".to_owned(),
        },
    )
    .await;
}

你可以在 examples/docs.rs 的文档中看到更多有用的示例。

强烈建议您阅读以下代码示例:[hello_world_bot](https://github.com/LasterAlex/teloxide_tests/blob/master/examples/hello_world_bot/src/main.rs)(其中包含大量注释,解释如何使用此crate,我在README中删除了它们)和[calculator_bot](https://github.com/LasterAlex/teloxide_tests/blob/master/examples/calculator_bot/src/tests.rs)(介绍语法糖和与对话交互)。

如何实现它?

希望它像在./examples中发生的那样简单。

  1. 导入teloxide_tests
  2. 将处理树转换为单独的函数(我们毕竟是要对其进行测试)。
  3. 创建一个模拟机器人,它可以是任何可以转换为更新的东西,例如MockMessageText或MockMessagePhoto。
  4. 添加依赖项或不同的机器人,使用.dependencies(deps![]).me(MockedMe::new().build())
  5. 使用.dispatch().await分发它。
  6. 使用.get_responses()获取响应。
  7. 使用获取的响应进行测试。
  8. 如果您想使用新的更新重用当前的机器人和状态,只需调用.update(MockMessageText::new())并从第5步开始!

不要使用原始MockBot字段(如bot.updates或bot.me)来修改机器人,除非您知道自己在做什么。使用给定的抽象,如果某些功能缺失,您可以在github仓库(或写入Telegram群组@teloxide_tests)中提及。

陷阱

  1. 竞态条件。据我所知,这是最困难的。

  2. 并且当您使用此crate尚不支持的方法时。请参阅文档以查看最新版本中实现了哪些端点(或查看server/routes文件以查看当前端点)。

  3. 也许还有这样一个事实,即模拟服务器实际上检查存在的消息和文件,并且它从干净的状态开始。您不能仅通过file_id发送文件或通过任意旧的message_id转发消息,因为机器人不知道如何处理它们,所以您需要通过将更新分发给机器人来单独添加它们,以便将其作为用户消息添加到内存中(您可以在模拟结构中将file_id和message_id更改为所需的内容)。

与这些竞态条件相关的某些错误

  • 未为std::sync::MutexGuard<'static, ()>实现Send特性和

    这意味着您不能在任意线程之间共享机器人,您在任何情况下都不应该这样做。

  • PoisonError(...)

    您不应该看到它,我尝试减轻它,但如果您看到了,这不是问题,这意味着其他某物崩溃了,现在机器人不知道该怎么做。只需修复导致问题的任何内容,poison errors应该会消失。

  • 每次运行测试时都会改变的白痴错误

    您可以使用crate serial_test,或者尝试在每次测试的末尾添加drop(bot);,并在调用MockBot::new()之后做所有事情,因为机器人的创建创建了一个安全的锁,以防止任何竞态条件。

贡献

请参阅 CONTRIBUTING.md

待办事项

  • 添加数据集
    • 添加聊天数据集
    • 添加常用消息数据集
    • 添加查询数据集(低优先级)
    • 添加消息数据集(低优先级)
    • 添加无类别结构(低优先级)
  • 添加模拟服务器
    • 添加最常见的端点
    • 添加所有常用消息
    • 添加内联查询(低优先级)
    • 添加所有查询(低优先级)
    • 添加所有消息(极低优先级)
    • 添加其他所有内容(可能永远都不会完成)
  • 创建一个向模拟服务器发送请求的模拟机器人
  • 向该机器人添加测试
  • 将其制作成库
  • 准备就绪后发布

特别感谢

teloxide 团队!他们创建了一个绝对令人难以置信的库,拥有出色的内部文档,这在开发过程中帮助了我很多!这是一个惊人的项目,我很高兴能够为它添加一些有用的东西!

依赖关系

~28–45MB
~816K SLoC