重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
testing-python by jlowin/fastmcp
npx skills add https://github.com/jlowin/fastmcp --skill testing-python每个测试都应该是原子化的、自包含的,并且测试单一功能。测试多个内容的测试更难调试和维护。
每个测试应验证单一行为。测试名称应在失败时告诉你哪里出了问题。当多个断言都验证同一行为时,使用多个断言是可以接受的。
# 良好:名称告诉你哪里出错了
def test_user_creation_sets_defaults():
user = User(name="Alice")
assert user.role == "member"
assert user.id is not None
assert user.created_at is not None
# 不佳:如果这个测试失败,是哪个行为出错了?
def test_user():
user = User(name="Alice")
assert user.role == "member"
user.promote()
assert user.role == "admin"
assert user.can_delete_others()
import pytest
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("World", "WORLD"),
("", ""),
("123", "123"),
])
def test_uppercase_conversion(input, expected):
assert input.upper() == expected
不要对不相关的行为进行参数化。如果测试逻辑不同,请编写独立的测试。
本项目全局使用 。编写异步测试时无需装饰器:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
asyncio_mode = "auto"# 正确
async def test_async_operation():
result = await some_async_function()
assert result == expected
# 错误 - 不要添加这个
@pytest.mark.asyncio
async def test_async_operation():
...
将所有导入语句放在文件顶部:
# 正确
import pytest
from fastmcp import FastMCP
from fastmcp.client import Client
async def test_something():
mcp = FastMCP("test")
...
# 错误 - 不要使用局部导入
async def test_something():
from fastmcp import FastMCP # 不要这样做
...
将 FastMCP 服务器直接传递给客户端:
from fastmcp import FastMCP
from fastmcp.client import Client
mcp = FastMCP("TestServer")
@mcp.tool
def greet(name: str) -> str:
return f"Hello, {name}!"
async def test_greet_tool():
async with Client(mcp) as client:
result = await client.call_tool("greet", {"name": "World"})
assert result[0].text == "Hello, World!"
仅在明确测试网络功能时才使用 HTTP 传输。
测试 JSON 模式和复杂结构时使用 inline-snapshot:
from inline_snapshot import snapshot
def test_schema_generation():
schema = generate_schema(MyModel)
assert schema == snapshot() # 首次运行时会自动填充
命令:
pytest --inline-snapshot=create - 填充空快照pytest --inline-snapshot=fix - 在有意更改后更新@pytest.fixture
def client():
return Client()
async def test_with_client(client):
result = await client.ping()
assert result is not None
tmp_pathdef test_file_writing(tmp_path):
file = tmp_path / "test.txt"
file.write_text("content")
assert file.read_text() == "content"
from unittest.mock import patch, AsyncMock
async def test_external_api_call():
with patch("mymodule.external_client.fetch", new_callable=AsyncMock) as mock:
mock.return_value = {"data": "test"}
result = await my_function()
assert result == {"data": "test"}
尽可能使用真实实现测试你的代码。模拟外部服务,而不是内部类。
使用描述性名称来解释场景:
# 良好
def test_login_fails_with_invalid_password():
def test_user_can_update_own_profile():
def test_admin_can_delete_any_user():
# 不佳
def test_login():
def test_update():
def test_delete():
import pytest
def test_raises_on_invalid_input():
with pytest.raises(ValueError, match="must be positive"):
calculate(-1)
async def test_async_raises():
with pytest.raises(ConnectionError):
await connect_to_invalid_host()
uv run pytest -n auto # 并行运行所有测试
uv run pytest -n auto -x # 在首次失败时停止
uv run pytest path/to/test.py # 运行特定文件
uv run pytest -k "test_name" # 运行匹配模式的测试
uv run pytest -m "not integration" # 排除集成测试
提交测试前:
@pytest.mark.asyncio 装饰器每周安装量
64
代码仓库
GitHub 星标数
24.0K
首次出现
2026年1月20日
安全审计
已安装于
codex57
opencode57
claude-code56
gemini-cli55
cursor54
antigravity52
Every test should be atomic , self-contained , and test single functionality. A test that tests multiple things is harder to debug and maintain.
Each test should verify a single behavior. The test name should tell you what's broken when it fails. Multiple assertions are fine when they all verify the same behavior.
# Good: Name tells you what's broken
def test_user_creation_sets_defaults():
user = User(name="Alice")
assert user.role == "member"
assert user.id is not None
assert user.created_at is not None
# Bad: If this fails, what behavior is broken?
def test_user():
user = User(name="Alice")
assert user.role == "member"
user.promote()
assert user.role == "admin"
assert user.can_delete_others()
import pytest
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("World", "WORLD"),
("", ""),
("123", "123"),
])
def test_uppercase_conversion(input, expected):
assert input.upper() == expected
Don't parameterize unrelated behaviors. If the test logic differs, write separate tests.
This project uses asyncio_mode = "auto" globally. Write async tests without decorators:
# Correct
async def test_async_operation():
result = await some_async_function()
assert result == expected
# Wrong - don't add this
@pytest.mark.asyncio
async def test_async_operation():
...
Put ALL imports at the top of the file:
# Correct
import pytest
from fastmcp import FastMCP
from fastmcp.client import Client
async def test_something():
mcp = FastMCP("test")
...
# Wrong - no local imports
async def test_something():
from fastmcp import FastMCP # Don't do this
...
Pass FastMCP servers directly to clients:
from fastmcp import FastMCP
from fastmcp.client import Client
mcp = FastMCP("TestServer")
@mcp.tool
def greet(name: str) -> str:
return f"Hello, {name}!"
async def test_greet_tool():
async with Client(mcp) as client:
result = await client.call_tool("greet", {"name": "World"})
assert result[0].text == "Hello, World!"
Only use HTTP transport when explicitly testing network features.
Use inline-snapshot for testing JSON schemas and complex structures:
from inline_snapshot import snapshot
def test_schema_generation():
schema = generate_schema(MyModel)
assert schema == snapshot() # Will auto-populate on first run
Commands:
pytest --inline-snapshot=create - populate empty snapshotspytest --inline-snapshot=fix - update after intentional changes@pytest.fixture
def client():
return Client()
async def test_with_client(client):
result = await client.ping()
assert result is not None
tmp_path for file operationsdef test_file_writing(tmp_path):
file = tmp_path / "test.txt"
file.write_text("content")
assert file.read_text() == "content"
from unittest.mock import patch, AsyncMock
async def test_external_api_call():
with patch("mymodule.external_client.fetch", new_callable=AsyncMock) as mock:
mock.return_value = {"data": "test"}
result = await my_function()
assert result == {"data": "test"}
Test your code with real implementations when possible. Mock external services, not internal classes.
Use descriptive names that explain the scenario:
# Good
def test_login_fails_with_invalid_password():
def test_user_can_update_own_profile():
def test_admin_can_delete_any_user():
# Bad
def test_login():
def test_update():
def test_delete():
import pytest
def test_raises_on_invalid_input():
with pytest.raises(ValueError, match="must be positive"):
calculate(-1)
async def test_async_raises():
with pytest.raises(ConnectionError):
await connect_to_invalid_host()
uv run pytest -n auto # Run all tests in parallel
uv run pytest -n auto -x # Stop on first failure
uv run pytest path/to/test.py # Run specific file
uv run pytest -k "test_name" # Run tests matching pattern
uv run pytest -m "not integration" # Exclude integration tests
Before submitting tests:
@pytest.mark.asyncio decoratorsWeekly Installs
64
Repository
GitHub Stars
24.0K
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex57
opencode57
claude-code56
gemini-cli55
cursor54
antigravity52
agent-browser 浏览器自动化工具 - Vercel Labs 命令行网页操作与测试
174,900 周安装