示例成品 · 平台演示,按左边这组点选真跑出来的
先别改原函数。用 pytest 的 `monkeypatch` 把“全局配置”和“当前时间”临时换掉,就能测,不用动生产代码,零改动风险。
假设代码在 `user_status.py`:
```python
from datetime import datetime
def get_user_status():
config = get_global_config()
now = datetime.now()
if now.hour < 9:
return 'off'
return config.get('status', 'on')
```
测试文件 `test_user_status.py`:
```python
from types import SimpleNamespace
import user_status # 换成你实际文件名
def _冻结时间(monkeypatch, hour):
# 造一个假的 datetime,让 datetime.now() 返回指定的 hour
fake_now = SimpleNamespace(hour=hour)
fake_datetime = SimpleNamespace(now=lambda: fake_now)
monkeypatch.setattr(user_status, "datetime", fake_datetime)
def test_9点前直接off(monkeypatch):
monkeypatch.setattr(user_status, "get_global_config", lambda: {"status": "on"})
_冻结时间(monkeypatch, 8)
assert user_status.get_user_status() == "off"
def test_9点整走配置且有值(monkeypatch):
monkeypatch.setattr(user_status, "get_global_config", lambda: {"status": "busy"})
_冻结时间(monkeypatch, 9)
assert user_status.get_user_status() == "busy"
def test_9点后配置没有status用默认on(monkeypatch):
monkeypatch.setattr(user_status, "get_global_config", lambda: {})
_冻结时间(monkeypatch, 10)
assert user_status.get_user_status() == "on"
```
运行:
```bash
pip install pytest
pytest test_user_status.py -v
```
这 3 个测试先保核心路径:
- 9 点前:不管配置,直接 `off`
- 9 点整及以后:配置里有 `status` 就用配置的值
- 9 点后:配置里没有 `status`,用默认 `on`
注意我故意测了 `9` 点整,因为 `hour < 9` 不包含 9,这个边界要固定下来。
---
如果你以后想少写这种 mock,可以再做一个向后兼容的小改动:
```python
def get_user_status(config=None, now=None):
if config is None:
config = get_global_config()
if now is None:
now = datetime.now()
if now.hour < 9:
return 'off'
return config.get('status', 'on')
```
这个改动对老调用 `get_user_status()` 完全没影响,只是给测试留了口子。测试可以直接传参:
```python
def test_9点前直接off():
assert get_user_status(
config={"status": "on"},
now=SimpleNamespace(hour=8)
) == "off"
```
但如果你现在最怕改炸锅,就先用上面那套 `monkeypatch` 测试,不用改原函数。
点左边「开工 · 直接出成品」,出一份你自己的版本(文字免费)