60e0ffc959
Upgrade checks / Notify on failure (push) Has been cancelled
Upgrade checks / Close issue on success (push) Has been cancelled
Schema Crash Test / Real-world schema crash test (232K schemas) (push) Has been cancelled
Run static analysis / static_analysis (push) Has been cancelled
Tests / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Tests / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Tests / Tests with lowest-direct dependencies (push) Has been cancelled
Tests / MCP conformance tests (push) Has been cancelled
Tests / Integration tests (push) Has been cancelled
Tests / Package install smoke (push) Has been cancelled
Upgrade checks / Static analysis (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.13 on ubuntu-latest (push) Has been cancelled
Upgrade checks / Tests: Python 3.10 on windows-latest (push) Has been cancelled
Upgrade checks / Integration tests (push) Has been cancelled
Update MCPServerConfig Schema / update-config-schema (push) Has been cancelled
Update SDK Documentation / update-sdk-docs (push) Has been cancelled
161 lines
5.1 KiB
Python
161 lines
5.1 KiB
Python
"""
|
|
Tests for the Testing Demo server.
|
|
|
|
Demonstrates pytest-asyncio patterns, fixtures, and testing best practices.
|
|
"""
|
|
|
|
import pytest
|
|
from dirty_equals import IsStr
|
|
|
|
from fastmcp.client import Client
|
|
|
|
|
|
@pytest.fixture
|
|
async def client():
|
|
"""
|
|
Client fixture for testing.
|
|
|
|
Uses async context manager and yields client synchronously.
|
|
No @pytest.mark.asyncio needed - asyncio_mode = "auto" handles it.
|
|
"""
|
|
# Import here to avoid import-time side effects
|
|
from server import mcp
|
|
|
|
async with Client(mcp) as client:
|
|
yield client
|
|
|
|
|
|
async def test_add_tool(client: Client):
|
|
"""Test the add tool with simple addition"""
|
|
result = await client.call_tool("add", {"a": 2, "b": 3})
|
|
assert result.data == 5
|
|
|
|
|
|
async def test_greet_tool_default(client: Client):
|
|
"""Test the greet tool with default greeting"""
|
|
result = await client.call_tool("greet", {"name": "Alice"})
|
|
assert result.data == "Hello, Alice!"
|
|
|
|
|
|
async def test_greet_tool_custom(client: Client):
|
|
"""Test the greet tool with custom greeting"""
|
|
result = await client.call_tool("greet", {"name": "Bob", "greeting": "Hi"})
|
|
assert result.data == "Hi, Bob!"
|
|
|
|
|
|
async def test_async_multiply_tool(client: Client):
|
|
"""Test the async multiply tool"""
|
|
result = await client.call_tool("async_multiply", {"x": 3.5, "y": 2.0})
|
|
assert result.data == 7.0
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"a,b,expected",
|
|
[
|
|
(0, 0, 0),
|
|
(1, 1, 2),
|
|
(-1, 1, 0),
|
|
(100, 200, 300),
|
|
],
|
|
)
|
|
async def test_add_parametrized(client: Client, a: int, b: int, expected: int):
|
|
"""Test add tool with multiple parameter combinations"""
|
|
result = await client.call_tool("add", {"a": a, "b": b})
|
|
assert result.data == expected
|
|
|
|
|
|
async def test_server_info_resource(client: Client):
|
|
"""Test the server info resource"""
|
|
result = await client.read_resource("demo://info")
|
|
assert len(result) == 1
|
|
assert result[0].text == "This is the FastMCP Testing Demo server"
|
|
|
|
|
|
async def test_greeting_resource_template(client: Client):
|
|
"""Test the greeting resource template"""
|
|
result = await client.read_resource("demo://greeting/Charlie")
|
|
assert len(result) == 1
|
|
assert result[0].text == "Welcome to FastMCP, Charlie!"
|
|
|
|
|
|
async def test_hello_prompt_default(client: Client):
|
|
"""Test hello prompt with default parameter"""
|
|
result = await client.get_prompt("hello")
|
|
assert result.messages[0].content.text == "Say hello to World in a friendly way."
|
|
|
|
|
|
async def test_hello_prompt_custom(client: Client):
|
|
"""Test hello prompt with custom name"""
|
|
result = await client.get_prompt("hello", {"name": "Dave"})
|
|
assert result.messages[0].content.text == "Say hello to Dave in a friendly way."
|
|
|
|
|
|
async def test_explain_prompt_levels(client: Client):
|
|
"""Test explain prompt with different detail levels"""
|
|
# Simple level
|
|
result = await client.get_prompt(
|
|
"explain", {"topic": "MCP", "detail_level": "simple"}
|
|
)
|
|
assert "simple terms" in result.messages[0].content.text
|
|
assert "MCP" in result.messages[0].content.text
|
|
|
|
# Detailed level
|
|
result = await client.get_prompt(
|
|
"explain", {"topic": "MCP", "detail_level": "detailed"}
|
|
)
|
|
assert "detailed" in result.messages[0].content.text
|
|
assert "technical" in result.messages[0].content.text
|
|
|
|
|
|
async def test_list_tools(client: Client):
|
|
"""Test listing available tools"""
|
|
tools = await client.list_tools()
|
|
tool_names = [tool.name for tool in tools]
|
|
|
|
assert "add" in tool_names
|
|
assert "greet" in tool_names
|
|
assert "async_multiply" in tool_names
|
|
|
|
|
|
async def test_list_resources(client: Client):
|
|
"""Test listing available resources"""
|
|
resources = await client.list_resources()
|
|
resource_uris = [str(resource.uri) for resource in resources]
|
|
|
|
# Check that we have at least the static resource
|
|
assert "demo://info" in resource_uris
|
|
# There should be at least one resource listed
|
|
assert len(resource_uris) >= 1
|
|
|
|
|
|
async def test_list_prompts(client: Client):
|
|
"""Test listing available prompts"""
|
|
prompts = await client.list_prompts()
|
|
prompt_names = [prompt.name for prompt in prompts]
|
|
|
|
assert "hello" in prompt_names
|
|
assert "explain" in prompt_names
|
|
|
|
|
|
# Example using dirty-equals for flexible assertions
|
|
async def test_greet_with_dirty_equals(client: Client):
|
|
"""Test greet tool using dirty-equals for pattern matching"""
|
|
result = await client.call_tool("greet", {"name": "Eve"})
|
|
# Check that result data matches the pattern
|
|
assert result.data == IsStr(regex=r"^Hello, \w+!$")
|
|
|
|
|
|
# Example using inline-snapshot for complex data
|
|
async def test_tool_schema_structure(client: Client):
|
|
"""Test tool schema structure"""
|
|
tools = await client.list_tools()
|
|
add_tool = next(tool for tool in tools if tool.name == "add")
|
|
|
|
# Verify basic schema structure
|
|
assert add_tool.name == "add"
|
|
assert add_tool.description == "Add two numbers together"
|
|
assert "a" in add_tool.inputSchema["properties"]
|
|
assert "b" in add_tool.inputSchema["properties"]
|
|
assert add_tool.inputSchema["properties"]["a"]["type"] == "integer"
|
|
assert add_tool.inputSchema["properties"]["b"]["type"] == "integer"
|