1"use strict";(self.webpackChunknonebot=self.webpackChunknonebot||[]).push([["1484"],{60595(e,t,n){n.r(t),n.d(t,{metadata:()=>s,default:()=>h,frontMatter:()=>c,contentTitle:()=>l,toc:()=>p,assets:()=>d});var s=JSON.parse('{"id":"best-practice/testing/README","title":"\u914D\u7F6E\u4E0E\u6D4B\u8BD5\u4E8B\u4EF6\u54CD\u5E94\u5668","description":"\u4F7F\u7528 NoneBug \u8FDB\u884C\u5355\u5143\u6D4B\u8BD5","source":"@site/versioned_docs/version-2.4.3/best-practice/testing/README.mdx","sourceDirName":"best-practice/testing","slug":"/best-practice/testing/","permalink":"/docs/2.4.3/best-practice/testing/","draft":false,"unlisted":false,"editUrl":"https://github.com/nonebot/nonebot2/edit/master/website/versioned_docs/version-2.4.3/best-practice/testing/README.mdx","tags":[],"version":"2.4.3","lastUpdatedBy":"StarHeart","lastUpdatedAt":1785574664000,"sidebarPosition":1,"frontMatter":{"sidebar_position":1,"description":"\u4F7F\u7528 NoneBug \u8FDB\u884C\u5355\u5143\u6D4B\u8BD5","slug":"/best-practice/testing/"},"sidebar":"tutorial","previous":{"title":"\u63D2\u4EF6\u8DE8\u5E73\u53F0\u652F\u6301","permalink":"/docs/2.4.3/best-practice/multi-adapter"},"next":{"title":"\u6D4B\u8BD5\u4E8B\u4EF6\u54CD\u5E94\u4E0E\u4F1A\u8BDD\u64CD\u4F5C","permalink":"/docs/2.4.3/best-practice/testing/behavior"}}'),r=n(62540),a=n(43023),o=n(36031),i=n(84993);let c={sidebar_position:1,description:"\u4F7F\u7528 NoneBug \u8FDB\u884C\u5355\u5143\u6D4B\u8BD5",slug:"/best-practice/testing/"},l="\u914D\u7F6E\u4E0E\u6D4B\u8BD5\u4E8B\u4EF6\u54CD\u5E94\u5668",d={},p=[{value:"\u5B89\u88C5 NoneBug",id:"\u5B89\u88C5-nonebug",level:2},{value:"\u914D\u7F6E\u6D4B\u8BD5",id:"\u914D\u7F6E\u6D4B\u8BD5",level:2},{value:"\u7F16\u5199\u63D2\u4EF6\u6D4B\u8BD5",id:"\u7F16\u5199\u63D2\u4EF6\u6D4B\u8BD5",level:2}];function u(e){let t={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",strong:"strong",...(0,a.R)(),...e.components},{Details:n}=t;return n||function(e,t){throw Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"\u914D\u7F6E\u4E0E\u6D4B\u8BD5\u4E8B\u4EF6\u54CD\u5E94\u5668",children:"\u914D\u7F6E\u4E0E\u6D4B\u8BD5\u4E8B\u4EF6\u54CD\u5E94\u5668"})}),"\n","\n",(0,r.jsxs)(t.blockquote,{children:["\n",(0,r.jsx)(t.p,{children:"\u5728\u8BA1\u7B97\u673A\u7F16\u7A0B\u4E2D\uFF0C\u5355\u5143\u6D4B\u8BD5\uFF08Unit Testing\uFF09\u53C8\u79F0\u4E3A\u6A21\u5757\u6D4B\u8BD5\uFF0C\u662F\u9488\u5BF9\u7A0B\u5E8F\u6A21\u5757\uFF08\u8F6F\u4EF6\u8BBE\u8BA1\u7684\u6700\u5C0F\u5355\u4F4D\uFF09\u6765\u8FDB\u884C\u6B63\u786E\u6027\u68C0\u9A8C\u7684\u6D4B\u8BD5\u5DE5\u4F5C\u3002"}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["\u4E3A\u4E86\u4FDD\u8BC1\u4EE3\u7801\u7684\u6B63\u786E\u8FD0\u884C\uFF0C\u6211\u4EEC\u4E0D\u4EC5\u9700\u8981\u5BF9\u9519\u8BEF\u8FDB\u884C\u8DDF\u8E2A\uFF0C\u8FD8\u9700\u8981\u5BF9\u4EE3\u7801\u8FDB\u884C\u6B63\u786E\u6027\u68C0\u9A8C\uFF0C\u4E5F\u5C31\u662F\u6D4B\u8BD5\u3002NoneBot \u63D0\u4F9B\u4E86\u4E00\u4E2A\u6D4B\u8BD5\u5DE5\u5177\u2014\u2014NoneBug\uFF0C\u5B83\u662F\u4E00\u4E2A ",(0,r.jsx)(t.a,{href:"https://docs.pytest.org/en/stable/",children:"pytest"})," \u63D2\u4EF6\uFF0C\u53EF\u4EE5\u5E2E\u52A9\u6211\u4EEC\u4FBF\u6377\u5730\u8FDB\u884C\u5355\u5143\u6D4B\u8BD5\u3002"]}),"\n",(0,r.jsx)(t.admonition,{title:"\u63D0\u793A",type:"tip",children:(0,r.jsxs)(t.p,{children:["\u5EFA\u8BAE\u5728\u9605\u8BFB\u672C\u6587\u6863\u524D\u5148\u9605\u8BFB ",(0,r.jsx)(t.a,{href:"https://docs.pytest.org/en/stable/",children:"pytest \u5B98\u65B9\u6587\u6863"}),"\u6765\u4E86\u89E3 pytest \u7684\u76F8\u5173\u672F\u8BED\u548C\u57FA\u672C\u7528\u6CD5\u3002"]})}),"\n",(0,r.jsx)(t.h2,{id:"\u5B89\u88C5-nonebug",children:"\u5B89\u88C5 NoneBug"}),"\n",(0,r.jsxs)(t.p,{children:["\u5728",(0,r.jsx)(t.strong,{children:"\u9879\u76EE\u76EE\u5F55"}),"\u4E0B\u6FC0\u6D3B\u865A\u62DF\u73AF\u5883\u540E\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u5B89\u88C5 NoneBug\uFF1A"]}),"\n",(0,r.jsxs)(o.A,{groupId:"tool",children:[(0,r.jsx)(i.A,{value:"poetry",label:"Poetry",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"poetry add nonebug -G test\n"})})}),(0,r.jsx)(i.A,{value:"pdm",label:"PDM",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"pdm add nonebug -dG test\n"})})}),(0,r.jsx)(i.A,{value:"pip",label:"pip",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"pip install nonebug\n"})})})]}),"\n",(0,r.jsxs)(t.p,{children:["\u8981\u8FD0\u884C NoneBug \u6D4B\u8BD5\uFF0C\u8FD8\u9700\u8981\u989D\u5916\u5B89\u88C5 pytest \u5F02\u6B65\u63D2\u4EF6 ",(0,r.jsx)(t.code,{children:"pytest-asyncio"})," \u6216 ",(0,r.jsx)(t.code,{children:"anyio"})," \u4EE5\u652F\u6301\u5F02\u6B65\u6D4B\u8BD5\u3002\u6587\u6863\u4E2D\uFF0C\u6211\u4EEC\u4EE5 ",(0,r.jsx)(t.code,{children:"pytest-asyncio"})," \u4E3A\u4F8B\uFF1A"]}),"\n",(0,r.jsxs)(o.A,{groupId:"tool",children:[(0,r.jsx)(i.A,{value:"poetry",label:"Poetry",default:!0,children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"poetry add pytest-asyncio -G test\n"})})}),(0,r.jsx)(i.A,{value:"pdm",label:"PDM",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"pdm add pytest-asyncio -dG test\n"})})}),(0,r.jsx)(i.A,{value:"pip",label:"pip",children:(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-bash",children:"pip install pytest-asyncio\n"})})})]}),"\n",(0,r.jsx)(t.h2,{id:"\u914D\u7F6E\u6D4B\u8BD5",children:"\u914D\u7F6E\u6D4B\u8BD5"}),"\n",(0,r.jsx)(t.p,{children:"\u5728\u5F00\u59CB\u6D4B\u8BD5\u4E4B\u524D\uFF0C\u6211\u4EEC\u9700\u8981\u5BF9\u6D4B\u8BD5\u8FDB\u884C\u4E00\u4E9B\u914D\u7F6E\uFF0C\u4EE5\u6B63\u786E\u542F\u52A8\u6211\u4EEC\u7684\u673A\u5668\u4EBA\u3002"}),"\n",(0,r.jsxs)(t.p,{children:["\u9996\u5148\u6211\u4EEC\u9700\u8981\u914D\u7F6E pytest-asyncio\uFF0C\u5728 ",(0,r.jsx)(t.code,{children:"pyproject.toml"})," \u7684 pytest \u914D\u7F6E\u90E8\u5206\u6DFB\u52A0\uFF1A"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-toml",children:'[tool.pytest.ini_options]\nasyncio_mode = "auto"\nasyncio_default_fixture_loop_scope = "session"\
1n'})}),"\n",(0,r.jsxs)(t.p,{children:["\u7136\u540E\uFF0C\u6211\u4EEC\u5728 ",(0,r.jsx)(t.code,{children:"tests"})," \u76EE\u5F55\u4E0B\u65B0\u5EFA ",(0,r.jsx)(t.code,{children:"conftest.py"})," \u6587\u4EF6\uFF0C\u6DFB\u52A0\u4EE5\u4E0B\u5185\u5BB9\uFF1A"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-python",metastring:"title=tests/conftest.py",children:'import pytest\nimport nonebot\nfrom pytest_asyncio import is_async_test\n# \u5BFC\u5165\u9002\u914D\u5668\nfrom nonebot.adapters.console import Adapter as ConsoleAdapter\n\ndef pytest_collection_modifyitems(items: list[pytest.Item]):\n pytest_asyncio_tests = (item for item in items if is_async_test(item))\n session_scope_marker = pytest.mark.asyncio(loop_scope="session")\n for async_test in pytest_asyncio_tests:\n async_test.add_marker(session_scope_marker, append=False)\n\[email protected](scope="session", autouse=True)\nasync def after_nonebot_init(after_nonebot_init: None):\n # \u52A0\u8F7D\u9002\u914D\u5668\n driver = nonebot.get_driver()\n driver.register_adapter(ConsoleAdapter)\n\n # \u52A0\u8F7D\u63D2\u4EF6\n nonebot.load_from_toml("pyproject.toml")\n'})}),"\n",(0,r.jsxs)(t.p,{children:["\u8FD9\u6837\uFF0C\u6211\u4EEC\u5C31\u53EF\u4EE5\u5728\u6D4B\u8BD5\u4E2D\u4F7F\u7528\u673A\u5668\u4EBA\u7684\u63D2\u4EF6\u4E86\u3002\u901A\u5E38\uFF0C\u6211\u4EEC\u4E0D\u9700\u8981\u81EA\u884C\u521D\u59CB\u5316 NoneBot\uFF0CNoneBug \u5DF2\u7ECF\u4E3A\u6211\u4EEC\u8FD0\u884C\u4E86 ",(0,r.jsx)(t.code,{children:"nonebot.init()"}),"\u3002\u5982\u679C\u9700\u8981\u81EA\u5B9A\u4E49 NoneBot \u521D\u59CB\u5316\u7684\u53C2\u6570\uFF0C\u6211\u4EEC\u53EF\u4EE5\u5728 ",(0,r.jsx)(t.code,{children:"conftest.py"})," \u4E2D\u6DFB\u52A0 ",(0,r.jsx)(t.code,{children:"pytest_configure"})," \u94A9\u5B50\u51FD\u6570\u3002\u4F8B\u5982\uFF0C\u6211\u4EEC\u53EF\u4EE5\u4FEE\u6539 NoneBot \u914D\u7F6E\u73AF\u5883\u4E3A ",(0,r.jsx)(t.code,{children:"test"})," \u5E76\u4ECE\u73AF\u5883\u53D8\u91CF\u4E2D\u8F93\u5165\u914D\u7F6E\uFF1A"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-python",metastring:"{4,6,8-10} title=tests/conftest.py",children:'import os\n\nimport pytest\nfrom nonebug import NONEBOT_INIT_KWARGS\n\nos.environ["ENVIRONMENT"] = "test"\n\ndef pytest_configure(config: pytest.Config):\n config.stash[NONEBOT_INIT_KWARGS] = {"secret": os.getenv("INPUT_SECRET")}\n'})}),"\n",(0,r.jsxs)(t.p,{children:["NoneBug \u9ED8\u8BA4\u4E5F\u4F1A\u4E3A\u6211\u4EEC\u7BA1\u7406 lifespan \u7684 startup \u4E0E shutdown\u3002\u5982\u679C\u4E0D\u5E0C\u671B NoneBug \u7BA1\u7406 lifespan\uFF0C\u4F60\u53EF\u4EE5\u5728 ",(0,r.jsx)(t.code,{children:"pytest_configure"})," \u91CC\u6DFB\u52A0\u4EE5\u4E0B\u914D\u7F6E\uFF1A"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-python",children:"import pytest\nfrom nonebug import NONEBOT_START_LIFESPAN\n\ndef pytest_configure(config: pytest.Config):\n config.stash[NONEBOT_START_LIFESPAN] = False\n"})}),"\n",(0,r.jsx)(t.h2,{id:"\u7F16\u5199\u63D2\u4EF6\u6D4B\u8BD5",children:"\u7F16\u5199\u63D2\u4EF6\u6D4B\u8BD5"}),"\n",(0,r.jsxs)(t.p,{children:["\u5728\u914D\u7F6E\u5B8C\u6210\u63D2\u4EF6\u52A0\u8F7D\u540E\uFF0C\u6211\u4EEC\u5C31\u53EF\u4EE5\u5728\u6D4B\u8BD5\u4E2D\u4F7F\u7528\u63D2\u4EF6\u4E86\u3002NoneBug \u901A\u8FC7 pytest fixture ",(0,r.jsx)(t.code,{children:"app"})," \u63D0\u4F9B\u5404\u79CD\u6D4B\u8BD5\u65B9\u6CD5\uFF0C\u6211\u4EEC\u53EF\u4EE5\u5728\u6D4B\u8BD5\u4E2D\u4F7F\u7528\u5B83\u6765\u6D4B\u8BD5\u63D2\u4EF6\u3002\u73B0\u5728\uFF0C\u6211\u4EEC\u521B\u5EFA\u4E00\u4E2A\u6D4B\u8BD5\u811A\u672C\u6765\u6D4B\u8BD5",(0,r.jsx)(t.a,{href:"/docs/2.4.3/appendices/session-control",children:"\u6DF1\u5165\u6307\u5357"}),"\u4E2D\u7F16\u5199\u7684\u5929\u6C14\u63D2\u4EF6\u3002\u9996\u5148\uFF0C\u6211\u4EEC\u5148\u8981\u5BFC\u5165\u6211\u4EEC\u9700\u8981\u7684\u6A21\u5757\uFF1A"]}),"\n",(0,r.jsxs)(n,{children:[(0,r.jsx)("summary",{children:"\u63D2\u4EF6\u793A\u4F8B"}),(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-python",metastring:"title=weather/__init__.py",children:'from nonebot import on_command\nfrom nonebot.rule import to_me\
1nfrom nonebot.matcher import Matcher\nfrom nonebot.adapters import Message\nfrom nonebot.params import CommandArg, ArgPlainText\n\nweather = on_command("\u5929\u6C14", rule=to_me(), aliases={"weather", "\u5929\u6C14\u9884\u62A5"})\n\[email protected]()\nasync def handle_function(matcher: Matcher, args: Message = CommandArg()):\n if args.extract_plain_text():\n matcher.set_arg("location", args)\n\[email protected]("location", prompt="\u8BF7\u8F93\u5165\u5730\u540D")\nasync def got_location(location: str = ArgPlainText()):\n if location not in ["\u5317\u4EAC", "\u4E0A\u6D77", "\u5E7F\u5DDE", "\u6DF1\u5733"]:\n await weather.reject(f"\u4F60\u60F3\u67E5\u8BE2\u7684\u57CE\u5E02 {location} \u6682\u4E0D\u652F\u6301\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\uFF01")\n await weather.finish(f"\u4ECA\u5929{location}\u7684\u5929\u6C14\u662F...")\n'})})]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-python",metastring:"{4,5,9,11-16} title=tests/test_weather.py",children:'from datetime import datetime\n\nimport pytest\nfrom nonebug import App\nfrom nonebot.adapters.console import User, Message, MessageEvent\n\[email protected]\nasync def test_weather(app: App):\n from awesome_bot.plugins.weather import weather\n\n event = MessageEvent(\n time=datetime.now(),\n self_id="test",\n message=Message("/\u5929\u6C14 \u5317\u4EAC"),\n user=User(id="user"),\n )\n'})}),"\n",(0,r.jsxs)(t.p,{children:["\u5728\u4E0A\u9762\u7684\u4EE3\u7801\u4E2D\uFF0C\u6211\u4EEC\u5F15\u5165\u4E86 NoneBug \u7684\u6D4B\u8BD5 ",(0,r.jsx)(t.code,{children:"App"})," \u5BF9\u8C61\uFF0C\u4EE5\u53CA\u5FC5\u8981\u7684\u9002\u914D\u5668\u6D88\u606F\u4E0E\u4E8B\u4EF6\u5B9A\u4E49\u7B49\u3002\u5728\u6D4B\u8BD5\u51FD\u6570 ",(0,r.jsx)(t.code,{children:"test_weather"})," \u4E2D\uFF0C\u6211\u4EEC\u5BFC\u5165\u4E86\u8981\u8FDB\u884C\u6D4B\u8BD5\u7684\u4E8B\u4EF6\u54CD\u5E94\u5668 ",(0,r.jsx)(t.code,{children:"weather"}),"\u3002\u8BF7\u6CE8\u610F\uFF0C\u7531\u4E8E\u9700\u8981\u7B49\u5F85 NoneBot \u521D\u59CB\u5316\u5E76\u52A0\u8F7D\u63D2\u4EF6\u5B8C\u6BD5\uFF0C\u63D2\u4EF6\u5185\u5BB9\u5FC5\u987B\u5728",(0,r.jsx)(t.strong,{children:"\u6D4B\u8BD5\u51FD\u6570\u5185\u90E8"}),"\u8FDB\u884C\u5BFC\u5165\u3002\u7136\u540E\uFF0C\u6211\u4EEC\u521B\u5EFA\u4E86\u4E00\u4E2A ",(0,r.jsx)(t.code,{children:"MessageEvent"})," \u4E8B\u4EF6\u5BF9\u8C61\uFF0C\u5B83\u6A21\u62DF\u4E86\u4E00\u4E2A\u7528\u6237\u53D1\u9001\u4E86 ",(0,r.jsx)(t.code,{children:"/\u5929\u6C14 \u5317\u4EAC"})," \u7684\u6D88\u606F\u3002\u63A5\u4E0B\u6765\uFF0C\u6211\u4EEC\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"app.test_matcher"})," \u65B9\u6CD5\u6765\u6D4B\u8BD5 ",(0,r.jsx)(t.code,{children:"weather"})," \u4E8B\u4EF6\u54CD\u5E94\u5668\uFF1A"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-python",metastring:"{11-15} title=tests/test_weather.py",children:'@pytest.mark.asyncio\nasync def test_weather(app: App):\n from awesome_bot.plugins.weather import weather\n\n event = MessageEvent(\n time=datetime.now(),\n self_id="test",\n message=Message("/\u5929\u6C14 \u5317\u4EAC"),\n user=User(id="user"),\n )\n async with app.test_matcher(weather) as ctx:\n bot = ctx.create_bot()\n ctx.receive_event(bot, event)\n ctx.should_call_send(event, "\u4ECA\u5929\u5317\u4EAC\u7684\u5929\u6C14\u662F...", result=None)\n ctx.should_finished(weather)\n'})}),"\n",(0,r.jsxs)(t.p,{children:["\u8FD9\u91CC\u6211\u4EEC\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"async with"})," \u8BED\u53E5\u5E76\u901A\u8FC7\u53C2\u6570\u6307\u5B9A\u8981\u6D4B\u8BD5\u7684\u4E8B\u4EF6\u54CD\u5E94\u5668 ",(0,r.jsx)(t.code,{children:"weather"})," \u6765\u8FDB\u5165\u6D4B\u8BD5\u4E0A\u4E0B\u6587\u3002\u5728\u6D4B\u8BD5\u4E0A\u4E0B\u6587\u4E2D\uFF0C\u6211\u4EEC\u53EF\u4EE5\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"ctx.create_bot"})," \u65B9\u6CD5\u521B\u5EFA\u4E00\u4E2A\u865A\u62DF\u7684\u673A\u5668\u4EBA\u5B9E\u4F8B\uFF0C\u5E76\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"ctx.receive_event"})," \u65B9\u6CD5\u6765\u6A21\u62DF\u673A\u5668\u4EBA\u63A5\u6536\u5230\u6D88\u606F\u4E8B\u4EF6\u3002\u7136\u540E\uFF0C\u6211\u4EEC\u5C31\u53EF\u4EE5\u5B9A\u4E49\u9884\u671F\u884C\u4E3A\u6765\u6D4B\u8BD5\u673A\u5668\u4EBA\u662F\u5426\u6B63\u786E\u8FD0\u884C\u3002\u5728\u4E0A\u9762\u7684\u4EE3\u7801\u4
1E2D\uFF0C\u6211\u4EEC\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"ctx.should_call_send"})," \u65B9\u6CD5\u6765\u65AD\u8A00\u673A\u5668\u4EBA\u5E94\u8BE5\u53D1\u9001 ",(0,r.jsx)(t.code,{children:"\u4ECA\u5929\u5317\u4EAC\u7684\u5929\u6C14\u662F..."})," \u8FD9\u6761\u6D88\u606F\uFF0C\u5E76\u4E14\u5C06\u53D1\u9001\u51FD\u6570\u7684\u8C03\u7528\u7ED3\u679C\u4F5C\u4E3A\u7B2C\u4E09\u4E2A\u53C2\u6570\u8FD4\u56DE\u7ED9\u4E8B\u4EF6\u5904\u7406\u51FD\u6570\u3002\u5982\u679C\u65AD\u8A00\u5931\u8D25\uFF0C\u6D4B\u8BD5\u5C06\u4F1A\u4E0D\u901A\u8FC7\u3002\u6211\u4EEC\u4E5F\u53EF\u4EE5\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"ctx.should_finished"})," \u65B9\u6CD5\u6765\u65AD\u8A00\u673A\u5668\u4EBA\u5E94\u8BE5\u7ED3\u675F\u4F1A\u8BDD\u3002"]}),"\n",(0,r.jsx)(t.p,{children:"\u4E3A\u4E86\u6D4B\u8BD5\u66F4\u590D\u6742\u7684\u60C5\u51B5\uFF0C\u6211\u4EEC\u53EF\u4EE5\u4E3A\u6DFB\u52A0\u66F4\u591A\u7684\u6D4B\u8BD5\u7528\u4F8B\u3002\u4F8B\u5982\uFF0C\u6211\u4EEC\u53EF\u4EE5\u6D4B\u8BD5\u7528\u6237\u8F93\u5165\u4E86\u4E00\u4E2A\u4E0D\u652F\u6301\u7684\u5730\u540D\u65F6\u673A\u5668\u4EBA\u7684\u53CD\u5E94\uFF1A"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-python",metastring:"{17-21,23-26} title=tests/test_weather.py",children:'def make_event(message: str = "") -> MessageEvent:\n return MessageEvent(\n time=datetime.now(),\n self_id="test",\n message=Message(message),\n user=User(id="user"),\n )\n\[email protected]\nasync def test_weather(app: App):\n from awesome_bot.plugins.weather import weather\n\n async with app.test_matcher(weather) as ctx:\n ... # \u7701\u7565\u524D\u9762\u7684\u6D4B\u8BD5\u7528\u4F8B\n\n async with app.test_matcher(weather) as ctx:\n bot = ctx.create_bot()\n event = make_event("/\u5929\u6C14 \u5357\u4EAC")\n ctx.receive_event(bot, event)\n ctx.should_call_send(event, "\u4F60\u60F3\u67E5\u8BE2\u7684\u57CE\u5E02 \u5357\u4EAC \u6682\u4E0D\u652F\u6301\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165\uFF01", result=None)\n ctx.should_rejected(weather)\n\n event = make_event("\u5317\u4EAC")\n ctx.receive_event(bot, event)\n ctx.should_call_send(event, "\u4ECA\u5929\u5317\u4EAC\u7684\u5929\u6C14\u662F...", result=None)\n ctx.should_finished(weather)\n'})}),"\n",(0,r.jsxs)(t.p,{children:["\u5728\u4E0A\u9762\u7684\u4EE3\u7801\u4E2D\uFF0C\u6211\u4EEC\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"ctx.should_rejected"})," \u6765\u65AD\u8A00\u673A\u5668\u4EBA\u5E94\u8BE5\u8BF7\u6C42\u7528\u6237\u91CD\u65B0\u8F93\u5165\u3002\u7136\u540E\uFF0C\u6211\u4EEC\u518D\u6B21\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"ctx.receive_event"})," \u65B9\u6CD5\u6765\u6A21\u62DF\u7528\u6237\u56DE\u590D\u4E86 ",(0,r.jsx)(t.code,{children:"\u5317\u4EAC"}),"\uFF0C\u5E76\u4F7F\u7528 ",(0,r.jsx)(t.code,{children:"ctx.should_finished"})," \u6765\u65AD\u8A00\u673A\u5668\u4EBA\u5E94\u8BE5\u7ED3\u675F\u4F1A\u8BDD\u3002"]}),"\n",(0,r.jsx)(t.p,{children:"\u66F4\u591A\u7684 NoneBug \u7528\u6CD5\u5C06\u5728\u540E\u7EED\u7AE0\u8282\u4E2D\u4ECB\u7ECD\u3002"})]})}function h(e={}){let{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(u,{...e})}):u(e)}},90118(e,t,n){n.d(t,{OC:()=>u,O_:()=>x,uc:()=>m,vT:()=>d});var s=n(62540),r=n(63696),a=n(49519),o=n(92882),i=n(76274),c=n(635),l=n(56113);function d(e){return r.Children.toArray(e).filter(e=>"\n"!==e)}function p({value:e,tabValues:t}){return t.some(t=>t.value===e)}function u(e){let t,{defaultValue:n,queryString:s=!1,groupId:d}=e,u=function(e){let{values:t,children:n}=e;return(0,r.useMemo)(()=>{let e=t??r.Children.toArray(n).flatMap(e=>{if(!e)return[];if((0,r.isValidElement)(e)&&function(e){let{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return[e];let t="string"==typeof e.type?e.type:e.type.name;throw Error(`Docusaurus error: Bad <Tabs> child <${t}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop. 2If you do not want to pass on a "value" prop to the direct children of <Tabs>, you can also pass an explicit <Tabs values={...}> prop.`)}).map(({props:{value:e,label:t,attributes:n,default:s}})=>({value:e,label:t,attributes:n,default:s})),s=(0,c.XI)(e,(e,t)=>e.value===t.value);if(s.length>0)throw Error(`Docusaurus error: Duplicate values "${s.map(e=>`'${e.value}'`).join(", ")}" found in <Tabs>. Every value needs to be unique.`);return e},[t,n])}(e),[h,m]=(0,r.useState)(()=>(function({defaultValue:e,tabValues:t}){if(0===t.length)throw Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(e){if(!p({value:e,tabValues:t}))throw Error(`Docusaurus error: The <Tabs> has a defaultValue "${e}" but none of its children has the corresponding value. Available values are: ${t.map(e=>e.value).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return e}let n=t.find(e=>e.default)??t[0];if(!n)throw Error("Unexpected error: 0 tabValues");return n.value})({defaultValue:n,tabValues:u})),[x,f]=function({queryString:e=!1,groupId:t}){let n=(0,a.W6)(),s=function({queryString:e=!1,groupId:t}){if("string"==typeof e)return e;if(!1===e)return null;if(!0===e&&!t)throw Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return t??null}({queryString:e,groupId:t});return[(0,i.aZ)(s),(0,r.useCallback)(e=>{if(!s)return;let t=new URLSearchParams(n.location.search);t.set(s,e),n.replace({...n.location,search:t.toString()})},[s,n])]}({queryString:s,groupId:d}),[g,b]=function({groupId:e}){let t=e?`docusaurus.tab.${e}`:null,[n,s]=(0,l.Dv)(t);return[n,(0,r.useCallback)(e=>{t&&s.set(e)},[t,s])]}({groupId:d}),j=p({value:t=x??g,tabValues:u})?t:null;return(0,o.A)(()=>{j&&m(j)},[j]),{selectedValue:h,selectValue:(0,r.useCallback)(e=>{if(!p({value:e,tabValues:u}))throw Error(`Can't select invalid tab value=${e}`);m(e),f(e),b(e)},[f,b,u]),tabValues:u,lazy:e.lazy??!1,block:e.block??!1}}let h=(0,r.createContext)(null);function m(){let e=r.useContext(h);if(!e)throw Error("useTabsContext() must be used within a Tabs component");return e}function x(e){return(0,s.jsx)(h.Provider,{value:e.value,children:e.children})}},84993(e,t,n){n.d(t,{A:()=>i});var s=n(62540);n(63696);var r=n(11750),a=n(90118);function o({children:e,className:t,hidden:n}){return(0,s.jsx)("div",{role:"tabpanel",className:(0,r.A)("tab-panel",t),hidden:n,children:e})}function i({children:e,className:t,value:n}){let{selectedValue:r,lazy:c}=(0,a.uc)(),l=n===r;return!l&&c?null:(0,s.jsx)(o,{className:t,hidden:!l,children:e})}}
2,36031(e,t,n){n.d(t,{A:()=>u});var s=n(62540);n(63696);var r=n(11750),a=n(49130),o=n(90118),i=n(72489),c=n(48682);function l({className:e}){let{selectedValue:t,selectValue:n,tabValues:a,block:c}=(0,o.uc)(),d=[],{blockElementScrollPositionUntilNextRender:p}=(0,i.a_)(),u=e=>{let s=e.currentTarget,r=a[d.indexOf(s)].value;r!==t&&(p(s),n(r))},h=e=>{let t=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{let n=d.indexOf(e.currentTarget)+1;t=d[n]??d[0];break}case"ArrowLeft":{let n=d.indexOf(e.currentTarget)-1;t=d[n]??d[d.length-1]}}t?.focus()};return(0,s.jsx)("div",{className:"not-prose",children:(0,s.jsxs)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.A)("tabs tabs-list tabs-lifted",c&&"tabs-block",e),children:[a.map(({value:e,label:n,attributes:a})=>(0,s.jsx)("li",{role:"tab",tabIndex:t===e?0:-1,"aria-selected":t===e,ref:e=>{d.push(e)},onKeyDown:h,onClick:u,...a,className:(0,r.A)("tab tab-lifted tab-item",a?.className,t===e&&"tab-active tab-item-active"),children:n??e},e)),(0,s.jsx)("div",{className:"tab tab-lifted tab-item tab-spacer"})]})})}function d({children:e}){return(0,s.jsx)("div",{children:e})}function p({className:e,children:t}){return(0,s.jsxs)("div",{className:(0,r.A)(a.G.tabs.container,"tabs-container"),children:[(0,s.jsx)(l,{className:e}),(0,s.jsx)(d,{children:t})]})}function u(e){let t=(0,c.A)(),n=(0,o.OC)(e);return(0,s.jsx)(o.O_,{value:n,children:(0,s.jsx)(p,{className:e.className,children:(0,o.vT)(e.children)})},String(t))}},43023(e,t,n){n.d(t,{R:()=>o,x:()=>i});var s=n(63696);let r={},a=s.createContext(r);function o(e){let t=s.useContext(a);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),s.createElement(a.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.