Skip to content

Commit 0f24749

Browse files
committed
test: 使用 pytest-mock 重构测试
1 parent c269b6b commit 0f24749

File tree

9 files changed

+154
-246
lines changed

9 files changed

+154
-246
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ dev-dependencies = [
6868
"tomlkit>=0.13",
6969
# test
7070
"pytest>=8",
71+
"pytest-mock>=3",
7172
"pytest-xdist>=3",
7273
"pytest-cov>=5",
7374
]

tests/test_adapter/test_adapter.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ def test_adapter_raise_error(bot: Bot) -> None:
3030
class TestAdapter(Adapter[Event[Any], None]):
3131
@override
3232
async def run(self) -> None:
33-
"""运行适配器。"""
3433
self.bot.exit()
3534
raise RuntimeError
3635

tests/test_bot.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1+
from pytest_mock import MockerFixture
2+
13
from alicebot import Bot
24

35

4-
def test_bot_restart() -> None:
5-
flag = False
6+
def test_bot_restart(mocker: MockerFixture) -> None:
7+
mock = mocker.AsyncMock()
68

79
async def bot_run_hook(bot: Bot) -> None:
8-
nonlocal flag
9-
if flag:
10+
if mock.called:
1011
bot.exit()
1112
return
13+
await mock()
1214
bot.restart()
13-
flag = True
1415

1516
bot = Bot()
17+
spy = mocker.spy(bot, "restart")
1618
bot.bot_run_hook(bot_run_hook)
1719
bot.run()
18-
assert flag
20+
spy.assert_called_once()

tests/test_dependencies.py

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing_extensions import Self
66

77
import pytest
8+
from pytest_mock import MockerFixture
89

910
from alicebot.dependencies import Depends, solve_dependencies
1011

@@ -70,14 +71,9 @@ class Dependent:
7071

7172

7273
@pytest.mark.anyio
73-
async def test_depends_context_manager() -> None:
74-
enter_flag = False
75-
exit_flag = False
76-
74+
async def test_depends_context_manager(mocker: MockerFixture) -> None:
7775
class DepA:
7876
def __enter__(self) -> Self:
79-
nonlocal enter_flag
80-
enter_flag = True
8177
return self
8278

8379
def __exit__(
@@ -86,8 +82,7 @@ def __exit__(
8682
_exc_value: Optional[BaseException],
8783
_traceback: Optional[TracebackType],
8884
) -> None:
89-
nonlocal exit_flag
90-
exit_flag = True
85+
pass
9186

9287
class DepB:
9388
a: DepA = Depends()
@@ -96,6 +91,9 @@ class Dependent:
9691
a: DepA = Depends()
9792
b: DepB = Depends()
9893

94+
enter_spy = mocker.spy(DepA, "__enter__")
95+
exit_spy = mocker.spy(DepA, "__exit__")
96+
9997
obj = None
10098

10199
async with AsyncExitStack() as stack:
@@ -110,17 +108,14 @@ class Dependent:
110108
assert isinstance(obj.a, DepA)
111109
assert isinstance(obj.b, DepB)
112110
assert obj.b.a is obj.a
111+
enter_spy.assert_called_once()
112+
exit_spy.assert_called_once()
113113

114114

115115
@pytest.mark.anyio
116-
async def test_depends_async_context_manager() -> None:
117-
enter_flag = False
118-
exit_flag = False
119-
116+
async def test_depends_async_context_manager(mocker: MockerFixture) -> None:
120117
class DepA:
121118
async def __aenter__(self) -> Self:
122-
nonlocal enter_flag
123-
enter_flag = True
124119
return self
125120

126121
async def __aexit__(
@@ -129,8 +124,7 @@ async def __aexit__(
129124
_exc_value: Optional[BaseException],
130125
_traceback: Optional[TracebackType],
131126
) -> None:
132-
nonlocal exit_flag
133-
exit_flag = True
127+
pass
134128

135129
class DepB:
136130
a: DepA = Depends()
@@ -139,6 +133,9 @@ class Dependent:
139133
a: DepA = Depends()
140134
b: DepB = Depends()
141135

136+
aenter_spy = mocker.spy(DepA, "__aenter__")
137+
aexit_spy = mocker.spy(DepA, "__aexit__")
138+
142139
obj = None
143140

144141
async with AsyncExitStack() as stack:
@@ -153,23 +150,20 @@ class Dependent:
153150
assert isinstance(obj.a, DepA)
154151
assert isinstance(obj.b, DepB)
155152
assert obj.b.a is obj.a
156-
157-
assert enter_flag
158-
assert exit_flag
153+
aenter_spy.assert_called_once()
154+
aexit_spy.assert_called_once()
159155

160156

161157
@pytest.mark.anyio
162-
async def test_depends_generator() -> None:
163-
enter_flag = False
164-
exit_flag = False
158+
async def test_depends_generator(mocker: MockerFixture) -> None:
159+
mock = mocker.MagicMock()
165160

166161
class DepA: ...
167162

168163
def dep_a() -> Generator[DepA, None, None]:
169-
nonlocal enter_flag, exit_flag
170-
enter_flag = True
164+
mock("enter")
171165
yield DepA()
172-
exit_flag = True
166+
mock("exit")
173167

174168
class DepB:
175169
a = Depends(dep_a)
@@ -192,23 +186,19 @@ class Dependent:
192186
assert isinstance(obj.a, DepA)
193187
assert isinstance(obj.b, DepB)
194188
assert obj.b.a is obj.a
195-
196-
assert enter_flag
197-
assert exit_flag
189+
assert mock.call_args_list == [mocker.call("enter"), mocker.call("exit")]
198190

199191

200192
@pytest.mark.anyio
201-
async def test_depends_async_generator() -> None:
202-
enter_flag = False
203-
exit_flag = False
193+
async def test_depends_async_generator(mocker: MockerFixture) -> None:
194+
mock = mocker.AsyncMock()
204195

205196
class DepA: ...
206197

207198
async def dep_a() -> AsyncGenerator[DepA, None]:
208-
nonlocal enter_flag, exit_flag
209-
enter_flag = True
199+
await mock("enter")
210200
yield DepA()
211-
exit_flag = True
201+
await mock("exit")
212202

213203
class DepB:
214204
a = Depends(dep_a)
@@ -231,9 +221,7 @@ class Dependent:
231221
assert isinstance(obj.a, DepA)
232222
assert isinstance(obj.b, DepB)
233223
assert obj.b.a is obj.a
234-
235-
assert enter_flag
236-
assert exit_flag
224+
assert mock.call_args_list == [mocker.call("enter"), mocker.call("exit")]
237225

238226

239227
@pytest.mark.anyio

tests/test_hook.py

Lines changed: 27 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,54 @@
1-
from typing import Any
1+
from typing import Any, Callable
22

33
from fake_adapter import FakeAdapter, FakeMessageEvent
44

55
from alicebot import Adapter, Bot, Event
66

77

8-
def test_bot_run_hook() -> None: # noqa: PLR0915
9-
bot_run_hook_flag = False
10-
bot_exit_hook_flag = False
11-
adapter_startup_hook_flag = False
12-
adapter_run_hook_flag = False
13-
adapter_shutdown_hook_flag = False
14-
event_preprocessor_hook_flag = False
15-
event_postprocessor_hook_flag = False
8+
def test_bot_run_hook() -> None:
9+
hook_call_list: list[Callable[..., Any]] = []
10+
bot = Bot()
1611

12+
@bot.bot_run_hook
1713
async def bot_run_hook(_bot: Bot) -> None:
18-
nonlocal bot_run_hook_flag
19-
bot_run_hook_flag = True
20-
21-
assert bot_run_hook_flag
22-
assert not bot_exit_hook_flag
23-
assert not adapter_startup_hook_flag
24-
assert not adapter_run_hook_flag
25-
assert not adapter_shutdown_hook_flag
26-
assert not event_preprocessor_hook_flag
27-
assert not event_postprocessor_hook_flag
14+
hook_call_list.append(bot_run_hook)
2815

16+
@bot.bot_exit_hook
2917
async def bot_exit_hook(_bot: Bot) -> None:
30-
nonlocal bot_exit_hook_flag
31-
bot_exit_hook_flag = True
32-
33-
assert bot_run_hook_flag
34-
assert bot_exit_hook_flag
35-
assert adapter_startup_hook_flag
36-
assert adapter_run_hook_flag
37-
assert adapter_shutdown_hook_flag
38-
assert event_preprocessor_hook_flag
39-
assert event_postprocessor_hook_flag
18+
hook_call_list.append(bot_exit_hook)
4019

20+
@bot.adapter_startup_hook
4121
async def adapter_startup_hook(_adapter: Adapter[Any, Any]) -> None:
42-
nonlocal adapter_startup_hook_flag
43-
adapter_startup_hook_flag = True
44-
45-
assert bot_run_hook_flag
46-
assert not bot_exit_hook_flag
47-
assert adapter_startup_hook_flag
48-
assert not adapter_run_hook_flag
49-
assert not adapter_shutdown_hook_flag
50-
assert not event_preprocessor_hook_flag
51-
assert not event_postprocessor_hook_flag
22+
hook_call_list.append(adapter_startup_hook)
5223

24+
@bot.adapter_run_hook
5325
async def adapter_run_hook(_adapter: Adapter[Any, Any]) -> None:
54-
nonlocal adapter_run_hook_flag
55-
adapter_run_hook_flag = True
56-
57-
assert bot_run_hook_flag
58-
assert not bot_exit_hook_flag
59-
assert adapter_startup_hook_flag
60-
assert adapter_run_hook_flag
61-
assert not adapter_shutdown_hook_flag
62-
assert not event_preprocessor_hook_flag
63-
assert not event_postprocessor_hook_flag
26+
hook_call_list.append(adapter_run_hook)
6427

28+
@bot.adapter_shutdown_hook
6529
async def adapter_shutdown_hook(_adapter: Adapter[Any, Any]) -> None:
66-
nonlocal adapter_shutdown_hook_flag
67-
adapter_shutdown_hook_flag = True
68-
69-
assert bot_run_hook_flag
70-
assert not bot_exit_hook_flag
71-
assert adapter_startup_hook_flag
72-
assert adapter_run_hook_flag
73-
assert adapter_shutdown_hook_flag
74-
assert event_preprocessor_hook_flag
75-
assert event_postprocessor_hook_flag
30+
hook_call_list.append(adapter_shutdown_hook)
7631

32+
@bot.event_preprocessor_hook
7733
async def event_preprocessor_hook(_event: Event[Any]) -> None:
78-
nonlocal event_preprocessor_hook_flag
79-
event_preprocessor_hook_flag = True
80-
81-
assert bot_run_hook_flag
82-
assert not bot_exit_hook_flag
83-
assert adapter_startup_hook_flag
84-
assert adapter_run_hook_flag
85-
assert not adapter_shutdown_hook_flag
86-
assert event_preprocessor_hook_flag
87-
assert not event_postprocessor_hook_flag
34+
hook_call_list.append(event_preprocessor_hook)
8835

36+
@bot.event_postprocessor_hook
8937
async def event_postprocessor_hook(_event: Event[Any]) -> None:
90-
nonlocal event_postprocessor_hook_flag
91-
event_postprocessor_hook_flag = True
92-
93-
assert bot_run_hook_flag
94-
assert not bot_exit_hook_flag
95-
assert adapter_startup_hook_flag
96-
assert adapter_run_hook_flag
97-
assert not adapter_shutdown_hook_flag
98-
assert event_preprocessor_hook_flag
99-
assert event_postprocessor_hook_flag
100-
101-
bot = Bot()
102-
103-
bot.bot_run_hook(bot_run_hook)
104-
bot.bot_exit_hook(bot_exit_hook)
105-
bot.adapter_startup_hook(adapter_startup_hook)
106-
bot.adapter_run_hook(adapter_run_hook)
107-
bot.adapter_shutdown_hook(adapter_shutdown_hook)
108-
bot.event_preprocessor_hook(event_preprocessor_hook)
109-
bot.event_postprocessor_hook(event_postprocessor_hook)
38+
hook_call_list.append(event_postprocessor_hook)
11039

11140
FakeAdapter.set_event_factories(
11241
lambda self: FakeMessageEvent(adapter=self, type="message")
11342
)
11443
bot.load_adapters(FakeAdapter)
11544
bot.run()
11645

117-
assert bot_run_hook_flag
118-
assert bot_exit_hook_flag
119-
assert adapter_startup_hook_flag
120-
assert adapter_run_hook_flag
121-
assert adapter_shutdown_hook_flag
122-
assert event_preprocessor_hook_flag
123-
assert event_postprocessor_hook_flag
46+
assert hook_call_list == [
47+
bot_run_hook,
48+
adapter_startup_hook,
49+
adapter_run_hook,
50+
event_preprocessor_hook,
51+
event_postprocessor_hook,
52+
adapter_shutdown_hook,
53+
bot_exit_hook,
54+
]

0 commit comments

Comments
 (0)