2022-04-30 16:04:41 +08:00
|
|
|
|
---
|
|
|
|
|
sidebar_position: 1
|
|
|
|
|
description: 使用 NoneBug 测试机器人
|
|
|
|
|
slug: /advanced/unittest/
|
|
|
|
|
|
|
|
|
|
options:
|
|
|
|
|
menu:
|
2022-05-21 11:17:27 +08:00
|
|
|
|
weight: 70
|
2022-04-30 16:04:41 +08:00
|
|
|
|
category: advanced
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
import CodeBlock from "@theme/CodeBlock";
|
|
|
|
|
|
|
|
|
|
# 单元测试
|
|
|
|
|
|
|
|
|
|
[单元测试](https://zh.wikipedia.org/wiki/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95)
|
|
|
|
|
|
|
|
|
|
> 在计算机编程中,单元测试(Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。
|
|
|
|
|
|
|
|
|
|
NoneBot2 使用 [Pytest](https://docs.pytest.org) 单元测试框架搭配 [NoneBug](https://github.com/nonebot/nonebug) 插件进行单元测试,通过直接与事件响应器/适配器等交互简化测试流程,更易于编写。
|
|
|
|
|
|
|
|
|
|
## 安装 NoneBug
|
|
|
|
|
|
|
|
|
|
安装 NoneBug 时,Pytest 会作为依赖被一起安装。
|
|
|
|
|
|
|
|
|
|
要运行 NoneBug,还需要额外安装 Pytest 异步插件 `pytest-asyncio` 或 `anyio`,文档将以 `pytest-asyncio` 为例。
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
poetry add nonebug pytest-asyncio --dev
|
|
|
|
|
# 也可以通过 pip 安装
|
|
|
|
|
pip install nonebug pytest-asyncio
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
:::tip 提示
|
|
|
|
|
建议首先阅读 [Pytest 文档](https://docs.pytest.org) 理解相关术语。
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
## 加载插件
|
|
|
|
|
|
|
|
|
|
我们可以使用 Pytest **Fixtures** 来加载插件,下面是一个示例:
|
|
|
|
|
|
|
|
|
|
```python title=conftest.py
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
from typing import TYPE_CHECKING, Set
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
|
from nonebot.plugin import Plugin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def load_plugins(nonebug_init: None) -> Set["Plugin"]:
|
|
|
|
|
import nonebot # 这里的导入必须在函数内
|
|
|
|
|
|
|
|
|
|
# 加载插件
|
|
|
|
|
return nonebot.load_plugins("awesome_bot/plugins")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
此 Fixture 的 [`nonebug_init`](https://github.com/nonebot/nonebug/blob/master/nonebug/fixture.py) 形参也是一个 Fixture,用于初始化 NoneBug。
|
|
|
|
|
|
|
|
|
|
Fixture 名称 `load_plugins` 可以修改为其他名称,文档以 `load_plugins` 为例。需要加载插件时,在测试函数添加形参 `load_plugins` 即可。加载完成后即可使用 `import` 导入事件响应器。
|
|
|
|
|
|
|
|
|
|
## 测试流程
|
|
|
|
|
|
|
|
|
|
Pytest 会在函数开始前通过 Fixture `app`(nonebug_app) **初始化 NoneBug** 并返回 `App` 对象。
|
|
|
|
|
|
|
|
|
|
:::warning 警告
|
|
|
|
|
所有从 `nonebot` 导入模块的函数都需要首先初始化 NoneBug App,否则会发生不可预料的问题。
|
|
|
|
|
|
|
|
|
|
在每个测试函数结束时,NoneBug 会自动销毁所有与 NoneBot 相关的资源。所有与 NoneBot 相关的 import 应在函数内进行导入。
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
随后使用 `test_matcher` 等测试方法获取到 `Context` 上下文,通过上下文管理提供的方法(如 `should_call_send` 等)预定义行为。
|
|
|
|
|
|
|
|
|
|
在上下文管理器关闭时,`Context` 会调用 `run_test` 方法按照预定义行为对事件响应器进行断言(如:断言事件响应和 API 调用等)。
|
|
|
|
|
|
|
|
|
|
## 测试样例
|
|
|
|
|
|
|
|
|
|
:::tip 提示
|
|
|
|
|
将从 `utils` 导入的 `make_fake_message`,`make_fake_event` 替换为对应平台的消息/事件类型。
|
|
|
|
|
|
|
|
|
|
将 `load_example` 替换为加载插件的 Fixture 名称。
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
使用 NoneBug 的 `test_matcher` 可以模拟出一个事件流程。如下是一个简单的示例:
|
|
|
|
|
|
|
|
|
|
import WeatherSource from "!!raw-loader!@site/../tests/examples/weather.py";
|
|
|
|
|
import WeatherTest from "!!raw-loader!@site/../tests/test_examples/test_weather.py";
|
|
|
|
|
|
|
|
|
|
<CodeBlock className="language-python" title="test_weather.py">
|
|
|
|
|
{WeatherTest}
|
|
|
|
|
</CodeBlock>
|
|
|
|
|
|
|
|
|
|
<details>
|
|
|
|
|
<summary>示例插件</summary>
|
|
|
|
|
<CodeBlock className="language-python" title="examples/weather.py">
|
|
|
|
|
{WeatherSource}
|
|
|
|
|
</CodeBlock>
|
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
|
在测试用例编写完成后 ,可以使用下面的命令运行单元测试。
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
pytest test_weather.py
|
|
|
|
|
```
|