nonebot2/website/versioned_docs/version-2.0.0-beta.3/advanced/unittest
github-actions[bot] 9b45b77894 🔖 Release 2.0.0-beta.3
2022-05-20 10:21:32 +00:00
..
_category_.json 🔖 Release 2.0.0-beta.3 2022-05-20 10:21:32 +00:00
README.mdx 🔖 Release 2.0.0-beta.3 2022-05-20 10:21:32 +00:00
test-adapters.md 🔖 Release 2.0.0-beta.3 2022-05-20 10:21:32 +00:00
test-matcher-operation.md 🔖 Release 2.0.0-beta.3 2022-05-20 10:21:32 +00:00
test-matcher.md 🔖 Release 2.0.0-beta.3 2022-05-20 10:21:32 +00:00

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
sidebar_position: 1
description: 使用 NoneBug 测试机器人
slug: /advanced/unittest/

options:
  menu:
    weight: 80
    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
```