2个版本

0.1.1 2024年8月1日
0.1.0 2024年7月17日

#1894 in 过程宏

Download history 114/week @ 2024-07-17 13/week @ 2024-07-24 132/week @ 2024-07-31 6/week @ 2024-08-07

265 每月下载量
用于 teloxide_tests

MIT 许可证

13KB
225

teloxide_tests

一个crate,允许您轻松地对teloxide机器人进行单元测试!无需互联网、账户或其他任何东西!

此crate拥有的功能

示例

简化版 [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_responces() 获取响应
  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为所需的任何内容)。

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

  • 未实现trait Send for std::sync::MutexGuard<'static, ()>

    这意味着您不能在任意线程之间共享机器人,您绝对不应该这样做。

  • PoisonError(...)

    您不应该看到它,我试图减轻它,但如果您看到了,那不是问题,只是意味着其他某处发生了panic,现在机器人不知道该怎么做。只需修复导致问题的任何内容,poison错误就应该消失了。

  • 每次运行测试时都会改变的愚蠢的错误

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

贡献

请参阅 CONTRIBUTING.md

待办事项

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

特别感谢

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


lib.rs:

teloxide_tests crate 的过程宏

依赖项

~285–740KB
~18K SLoC