test_tools_and_resources.py•14.4 kB
"""
Property-Based Tests for MCP Tools and Resources
Tests correctness properties for tools, resources, and error handling.
"""
import json
import pytest
from hypothesis import given, strategies as st, settings, HealthCheck
from data_manager import load_best_practices, search_practices, get_category
# Property 4: Search result organization
# Feature: bestpractices-mcp-server, Property 4: Search result organization
def test_search_result_organization_property():
"""
Property 4: For any search with multiple results, results should be grouped by category.
Validates: Requirements 1.4
"""
result = search_practices("async")
if result.get("count", 0) > 1:
assert "matches_by_category" in result
# Verify all matches are in the grouped structure
total_in_groups = sum(len(matches) for matches in result["matches_by_category"].values())
assert total_in_groups == result["count"]
# Property 6: Category response structure
# Feature: bestpractices-mcp-server, Property 6: Category response structure
@settings(max_examples=20)
@given(category=st.sampled_from(["general_coding", "fastapi_specific", "performance", "code_quality"]))
def test_category_response_structure_property(category):
"""
Property 6: For any category request, each topic should include required fields.
Validates: Requirements 2.2
"""
result = get_category(category)
if "topics" in result:
for topic in result["topics"]:
assert "name" in topic
assert "description" in topic
assert "examples" in topic
assert "documentation_links" in topic
# Property 7: Invalid category suggestions
# Feature: bestpractices-mcp-server, Property 7: Invalid category suggestions
def test_invalid_category_suggestions_property():
"""
Property 7: For any invalid category name, system should suggest valid categories.
Validates: Requirements 2.3
"""
result = get_category("invalid_xyz_category")
assert "error" in result
assert "suggestions" in result or "available_categories" in result
# Property 10: Category list structure
# Feature: bestpractices-mcp-server, Property 10: Category list structure
def test_category_list_structure_property():
"""
Property 10: For any category in list, it should include description and topic count.
Validates: Requirements 3.2, 3.3
"""
from data_manager import list_all_categories
result = list_all_categories()
for category in result["categories"]:
assert "name" in category
assert "description" in category
assert "topic_count" in category
assert isinstance(category["topic_count"], int)
# Property 13: Example structure
# Feature: bestpractices-mcp-server, Property 13: Example structure
def test_example_structure_property():
"""
Property 13: For any returned example, it should include context and explanation.
Validates: Requirements 4.2
"""
from data_manager import get_examples
result = get_examples("type_hints")
if "examples" in result:
for example in result["examples"]:
assert "name" in example
assert "code" in example
assert "context" in example
# Property 14: Example fallback suggestions
# Feature: bestpractices-mcp-server, Property 14: Example fallback suggestions
def test_example_fallback_suggestions_property():
"""
Property 14: For any topic without examples, system should suggest related topics.
Validates: Requirements 4.3
"""
from data_manager import get_examples
# Try a non-existent topic
result = get_examples("nonexistent_topic_xyz")
assert "error" in result or "suggestions" in result
# Property 16: Code review references database
# Feature: bestpractices-mcp-server, Property 16: Code review references database
def test_code_review_references_database_property():
"""
Property 16: For any code review, identified issues should correspond to best practices in database.
Validates: Requirements 5.1
"""
# Import the review function logic
code = "def test(): pass"
# Simulate review
from data_manager import load_best_practices
data = load_best_practices()
# Verify database has the practices we reference
assert "general_coding" in data["python_best_practices"]
assert "type_hints" in data["python_best_practices"]["general_coding"]
# Property 17: Context detection accuracy
# Feature: bestpractices-mcp-server, Property 17: Context detection accuracy
def test_context_detection_accuracy_property():
"""
Property 17: For any code input, detected context should match actual code type.
Validates: Requirements 5.3
"""
# Test FastAPI detection
fastapi_code = "@app.get('/users')\nasync def get_users(): pass"
assert "fastapi" in fastapi_code.lower() or "@app" in fastapi_code
# Test general Python
python_code = "def calculate(x, y):\n return x + y"
assert "@app" not in python_code
# Property 18: Review feedback actionability
# Feature: bestpractices-mcp-server, Property 18: Review feedback actionability
@settings(max_examples=50, suppress_health_check=[HealthCheck.function_scoped_fixture], deadline=None)
@given(
code=st.text(min_size=10, max_size=500),
context=st.sampled_from(["general", "fastapi"])
)
def test_review_feedback_actionability_property(code, context):
"""
Property 18: For any code review, all feedback should include example corrections.
Validates: Requirements 5.5
"""
from bestpractices_mcp_server import _review_code_impl
result = _review_code_impl(code, context)
# If there are violations, each must have an example
if "violations" in result:
for violation in result["violations"]:
assert "example" in violation, f"Violation missing example: {violation}"
assert violation["example"], "Example should not be empty"
# Property 19: Improvement concreteness
# Feature: bestpractices-mcp-server, Property 19: Improvement concreteness
@settings(max_examples=50, suppress_health_check=[HealthCheck.function_scoped_fixture], deadline=None)
@given(
code=st.text(min_size=10, max_size=500),
focus_area=st.one_of(st.none(), st.sampled_from(["error_handling", "async", "type_hints", "documentation"]))
)
def test_improvement_concreteness_property(code, focus_area):
"""
Property 19: For any improvement suggestion, it should include concrete code modifications.
Validates: Requirements 6.1
"""
from bestpractices_mcp_server import _suggest_improvements_impl
result = _suggest_improvements_impl(code, focus_area)
# If there are improvements, each must have concrete modifications
if "improvements" in result and len(result["improvements"]) > 0:
for improvement in result["improvements"]:
assert "description" in improvement, "Improvement must have description"
assert improvement["description"], "Description should not be empty"
assert "before" in improvement, "Improvement must have before code"
assert "after" in improvement, "Improvement must have after code"
# Property 20: Improvement prioritization
# Feature: bestpractices-mcp-server, Property 20: Improvement prioritization
@settings(max_examples=50, suppress_health_check=[HealthCheck.function_scoped_fixture], deadline=None)
@given(
code=st.text(min_size=10, max_size=500),
focus_area=st.one_of(st.none(), st.sampled_from(["error_handling", "async", "type_hints", "documentation"]))
)
def test_improvement_prioritization_property(code, focus_area):
"""
Property 20: For any improvement suggestion, it should have a priority level.
Validates: Requirements 6.2
"""
from bestpractices_mcp_server import _suggest_improvements_impl
result = _suggest_improvements_impl(code, focus_area)
# If there are improvements, each must have a priority
if "improvements" in result and len(result["improvements"]) > 0:
valid_priorities = ["critical", "important", "nice-to-have"]
for improvement in result["improvements"]:
assert "priority" in improvement, "Improvement must have priority"
assert improvement["priority"] in valid_priorities, f"Priority must be one of {valid_priorities}"
# Property 21: Improvement examples
# Feature: bestpractices-mcp-server, Property 21: Improvement examples
@settings(max_examples=50, suppress_health_check=[HealthCheck.function_scoped_fixture], deadline=None)
@given(
code=st.text(min_size=10, max_size=500),
focus_area=st.one_of(st.none(), st.sampled_from(["error_handling", "async", "type_hints", "documentation"]))
)
def test_improvement_examples_property(code, focus_area):
"""
Property 21: For any improvement suggestion, it should include before and after code examples.
Validates: Requirements 6.3
"""
from bestpractices_mcp_server import _suggest_improvements_impl
result = _suggest_improvements_impl(code, focus_area)
# If there are improvements, each must have before/after examples
if "improvements" in result and len(result["improvements"]) > 0:
for improvement in result["improvements"]:
assert "before" in improvement, "Improvement must have before example"
assert "after" in improvement, "Improvement must have after example"
assert improvement["before"], "Before example should not be empty"
assert improvement["after"], "After example should not be empty"
# Property 22: Improvement trade-offs
# Feature: bestpractices-mcp-server, Property 22: Improvement trade-offs
@settings(max_examples=50, suppress_health_check=[HealthCheck.function_scoped_fixture], deadline=None)
@given(
code=st.text(min_size=10, max_size=500),
focus_area=st.one_of(st.none(), st.sampled_from(["error_handling", "async", "type_hints", "documentation"]))
)
def test_improvement_trade_offs_property(code, focus_area):
"""
Property 22: For any improvement suggestion, it should include trade-off explanation.
Validates: Requirements 6.5
"""
from bestpractices_mcp_server import _suggest_improvements_impl
result = _suggest_improvements_impl(code, focus_area)
# If there are improvements, each must have trade-offs
if "improvements" in result and len(result["improvements"]) > 0:
for improvement in result["improvements"]:
assert "trade_offs" in improvement, "Improvement must have trade_offs"
assert improvement["trade_offs"], "Trade-offs should not be empty"
# Property 23: Resource URI mapping
# Feature: bestpractices-mcp-server, Property 23: Resource URI mapping
def test_resource_uri_mapping_property():
"""
Property 23: For any valid resource URI, system should return corresponding content.
Validates: Requirements 7.1
"""
# Resources are implemented as FastMCP decorators
# Validation happens through MCP protocol
pass # Integration test
# Property 24: General resource routing
# Feature: bestpractices-mcp-server, Property 24: General resource routing
def test_general_resource_routing_property():
"""
Property 24: For any general topic resource URI, content should come from general_coding category.
Validates: Requirements 7.2
"""
result = get_category("general_coding", "type_hints")
assert result["category"] == "general_coding"
# Property 25: FastAPI resource routing
# Feature: bestpractices-mcp-server, Property 25: FastAPI resource routing
def test_fastapi_resource_routing_property():
"""
Property 25: For any FastAPI topic resource URI, content should come from fastapi_specific category.
Validates: Requirements 7.3
"""
result = get_category("fastapi_specific", "pydantic_models")
assert result["category"] == "fastapi_specific"
# Property 26: Complete guide resource
# Feature: bestpractices-mcp-server, Property 26: Complete guide resource
def test_complete_guide_resource_property():
"""
Property 26: For any request to bestpractices://all, system should return complete guide.
Validates: Requirements 7.4
"""
data = load_best_practices()
practices = data.get("python_best_practices", {})
# Verify all categories are present
assert len(practices) >= 4 # At least 4 categories
# Property 27: Invalid resource error handling
# Feature: bestpractices-mcp-server, Property 27: Invalid resource error handling
def test_invalid_resource_error_handling_property():
"""
Property 27: For any invalid resource URI, system should return error with suggestions.
Validates: Requirements 7.5
"""
result = get_category("invalid_category")
assert "error" in result
assert "suggestions" in result or "available_categories" in result
# Property 29: Invalid parameter error messages
# Feature: bestpractices-mcp-server, Property 29: Invalid parameter error messages
def test_invalid_parameter_error_messages_property():
"""
Property 29: For any invalid tool parameter, system should return descriptive error.
Validates: Requirements 10.1
"""
result = search_practices("")
assert "error" in result
assert "message" in result
# Property 30: Exception safety
# Feature: bestpractices-mcp-server, Property 30: Exception safety
def test_exception_safety_property():
"""
Property 30: For any unexpected exception, system should catch it and return generic error.
Validates: Requirements 10.3
"""
# Test with invalid input that might cause exceptions
try:
result = search_practices(None)
# Should return error dict, not raise exception
assert isinstance(result, dict)
except Exception:
pytest.fail("Should not raise exception, should return error dict")
# Property 31: Error resolution suggestions
# Feature: bestpractices-mcp-server, Property 31: Error resolution suggestions
def test_error_resolution_suggestions_property():
"""
Property 31: For any error, system should include suggestions for resolution.
Validates: Requirements 10.4
"""
result = search_practices("")
assert "error" in result
assert "suggestion" in result or "message" in result