# BlenderMCP Test Suite
This directory contains the comprehensive BDD (Behavior-Driven Development) test suite for the BlenderMCP project.
## Overview
The test suite validates all behavioral specifications defined in the `features/` directory using pytest-bdd. Tests verify the MCP interface contracts, tool behaviors, and system properties.
**New in v1.3.0:** The suite now includes **Real Integration Tests** that run against a live, headless Blender instance to verify actual functionality.
## Test Architecture
### Design Principles
1. **Test Behaviors, Not Implementations**
- Tests validate observable behaviors and interface contracts
- No coupling to internal implementation details
- Focus on MCP tool schemas, return types, and error handling
2. **No Production Code Modifications**
- Tests are isolated to the `tests/` directory
- No changes to `src/` or `addon.py`
- Tests use mocks to simulate Blender responses
3. **Deterministic and Composable**
- All tests are deterministic (no randomness, no timing dependencies)
- Fixtures are reusable and composable
- Tests can run in any order
4. **Property-Based Testing**
- Hypothesis strategies are available for property-based tests
- Use for input validation, invariants, and edge cases
- Balance thoroughness with execution time
5. **Mirrored Source Structure**
- Test directory structure mirrors `src/` directory organization
- Makes it easy to find tests for specific modules
- Promotes logical grouping and maintainability
## Directory Structure
The test directory is organized to mirror the source code structure, making it intuitive to navigate between implementation and tests:
```
tests/
├── __init__.py # Test suite package
├── conftest.py # Shared fixtures and test infrastructure
├── README.md # This file
│
├── mcp/ # MCP server contract and interface tests
│ ├── __init__.py
│ ├── test_contract.py # Tool/resource/prompt discovery (feature 01)
│ ├── test_resources.py # Viewport screenshot resources (feature 11)
│ └── test_safety.py # Arbitrary code execution safety (feature 12)
│
├── tools/ # MCP tool wrapper tests (src/tools/)
│ ├── __init__.py
│ ├── test_mesh_analysis.py # Mesh statistics and topology (feature 02)
│ ├── test_remeshing.py # Voxel + QuadriFlow remeshing (features 03, 04)
│ ├── test_modifiers.py # Decimation + Shrinkwrap (features 05, 06)
│ ├── test_shading.py # UV seams and sharp edges (feature 07)
│ ├── test_viewport.py # Viewport controls and projection (feature 08)
│ └── test_scene.py # Model switching and config (feature 13)
│
├── retopo_tools/ # Retopology tool implementation tests (src/retopo_tools/)
│ ├── __init__.py
│ ├── test_baking.py # Normal map baking (feature 09)
│ ├── test_io.py # Import/export functionality (feature 10)
│ ├── test_camera.py # Camera ortho + batch renders (features 14, 15)
│ ├── test_retopoflow.py # RetopoFlow 4 add-on integration (features 16-22)
│ ├── test_quad_remesher.py # Quad Remesher add-on integration (feature 18)
│ ├── test_looptools.py # LoopTools add-on utilities (features 23-25)
│ ├── test_machin3tools.py # MACHIN3tools add-on integration (feature 26)
│ └── test_quadwrap.py # QuadWrap add-on integration (feature 27)
│
└── prompts/ # MCP prompt tests (src/prompts/)
└── __init__.py # (Prompt tests to be added)
├── integration/ # Real integration tests (requires Blender)
│ ├── conftest.py # Blender process management fixtures
│ ├── start_blender_server.py # Helper script to run inside Blender
│ ├── test_real_connection.py # Connection smoke tests
│ └── test_real_mesh_analysis.py # Functional tests with real geometry
```
### Test Organization Rationale
**tests/mcp/** - Tests for MCP server protocol compliance
- `test_contract.py`: Validates MCP tool/resource/prompt registration and schemas
- `test_resources.py`: Tests MCP resource endpoints (viewport screenshots)
- `test_safety.py`: Validates safety mechanisms for arbitrary code execution
**tests/tools/** - Tests for MCP tool wrappers in `src/tools/`
- Each test file corresponds to a tool module in `src/tools/`
- Consolidated tests where features share common implementation (e.g., remeshing, modifiers)
- Tests validate MCP interface contracts, not internal implementation
**tests/retopo_tools/** - Tests for underlying retopology implementations in `src/retopo_tools/`
- Tests the actual retopology tool logic used by MCP wrappers
- Validates complex workflows like baking, import/export, camera setup
- **NEW (Nov 2025)**: Extensive add-on integration tests for LLM-agent-retopologist
- RetopoFlow 4 (professional retopology suite)
- Quad Remesher (commercial auto-retopology)
- LoopTools (built-in mesh utilities)
- MACHIN3tools (pro modeling tools)
- QuadWrap (cylindrical topology automation)
**tests/prompts/** - Tests for MCP prompt definitions in `src/prompts/`
- Validates prompt structure and guidance quality
- (Tests to be expanded as prompts are added)
## Running Tests
### Prerequisites
Install test dependencies:
```bash
pip install pytest pytest-bdd hypothesis
```
### Run All Tests
```bash
# From repository root
pytest tests/
# With verbose output
pytest tests/ -v
# With coverage report
pytest tests/ --cov=src --cov-report=html
```
### Run Tests by Directory
```bash
# Run only MCP contract tests
pytest tests/mcp/ -v
# Run only tool wrapper tests
pytest tests/tools/ -v
# Run only retopology implementation tests
pytest tests/retopo_tools/ -v
```
### Run Specific Test Files
```bash
# Single test module
pytest tests/mcp/test_contract.py -v
# Multiple test modules
pytest tests/tools/test_mesh_analysis.py tests/tools/test_remeshing.py -v
```
### Run by Marker
```bash
# Unit tests only (no external dependencies)
pytest tests/ -m unit
# Contract compliance tests
pytest tests/ -m contract
# Integration tests (require Blender)
pytest tests/integration/ -v
```
### Real Integration Tests
The `tests/integration/` directory contains tests that launch a real Blender instance in background mode.
**Prerequisites:**
- A local installation of Blender (3.0+)
- The test runner will attempt to auto-locate `blender.exe` in standard paths.
**What they test:**
- Actual socket connection to the Blender addon
- Execution of Python code inside Blender
- Real return values from Blender API calls (e.g., accurate vertex counts)
**How to run:**
```bash
pytest tests/integration/ -v
```
### Run Specific Scenarios
```bash
# Run scenarios matching a pattern
pytest tests/ -k "voxel_remesh"
# Run specific scenario by name
pytest tests/tools/test_remeshing.py -k "default_settings"
```
## Test Coverage Status
### Current Test Results (as of 2025-11-10)
**Overall: 112 PASSED, 1 SKIPPED, 1 XFAIL out of 114 test scenarios**
Coverage: **100% scenario coverage** - All 27 feature files now have test implementations
Passing Rate: **98.2% of scenarios passing** (112/114 implemented scenarios pass)
**NEW: 27 test scenarios added for professional add-on integrations**
### Feature-by-Feature Breakdown
All 27 feature files now have corresponding test implementations:
#### MCP Contract Tests (tests/mcp/)
- **01_mcp_contract.feature** - MCP tool/resource/prompt discovery
- Status: 2/3 passing (1 xfail for resources not yet implemented)
- Location: `tests/mcp/test_contract.py`
- 50 tools registered and validated
- 2 prompts registered and validated
- **11_viewport_resource.feature** - Viewport screenshot resource
- Status: 6/6 passing
- Location: `tests/mcp/test_resources.py`
- Viewport screenshot functionality validated
- **12_safety.feature** - Arbitrary code execution safety
- Status: 4/4 passing
- Location: `tests/mcp/test_safety.py`
- Safety mechanisms validated
#### Tool Wrapper Tests (tests/tools/)
- **02_mesh_analysis.feature** - Mesh statistics and topology detection
- Status: 8/9 passing (1 skipped: flipped normals detection)
- Location: `tests/tools/test_mesh_analysis.py`
- All mesh stats and topology issue detection working
- **03_voxel_remesh.feature** + **04_quadriflow_remesh.feature** - Remeshing
- Status: 13/13 passing
- Location: `tests/tools/test_remeshing.py` (consolidated)
- Both voxel and QuadriFlow remeshing fully validated
- **05_decimation.feature** + **06_shrinkwrap.feature** - Modifiers
- Status: 10/10 passing
- Location: `tests/tools/test_modifiers.py` (consolidated)
- Decimation and shrinkwrap projection validated
- **07_seams_shading.feature** - UV seam and sharp edge marking
- Status: 7/7 passing
- Location: `tests/tools/test_shading.py`
- All seam and shading scenarios working
- **08_viewport_controls.feature** - Viewport projection and alignment
- Status: 10/10 passing
- Location: `tests/tools/test_viewport.py`
- All viewport control scenarios validated
- **13_model_switching.feature** - Client configuration generation
- Status: 5/5 passing
- Location: `tests/tools/test_scene.py`
- Model switching configurations validated
#### Retopology Implementation Tests (tests/retopo_tools/)
- **09_baking.feature** - Normal map baking
- Status: 7/7 passing
- Location: `tests/retopo_tools/test_baking.py`
- Baking workflow fully validated
- **10_import_export.feature** - Asset import/export
- Status: 8/8 passing
- Location: `tests/retopo_tools/test_io.py`
- Import/export functionality working
- **14_camera_ortho.feature** - Camera orthographic rendering
- Status: 5/5 passing
- Location: `tests/retopo_tools/test_camera.py`
- Orthographic camera setup working
- **15_batch_ortho_renders.feature** - Batch orthographic renders
- Status: 5/5 passing
- Location: `tests/retopo_tools/test_camera.py` (consolidated with feature 14)
- Batch rendering workflow validated
#### NEW: Add-on Integration Tests (tests/retopo_tools/)
- **16_draw_xray.feature** - RetopoFlow Draw Xray overlay
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_retopoflow.py`
- Clear retopology overlay visibility across modes
- **17_retopoflow_start.feature** - Start RetopoFlow session
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_retopoflow.py`
- Session initialization with snapping and overlay setup
- **18_quad_remesher.feature** - Quad Remesher auto-retopology
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_quad_remesher.py`
- Automatic quad base mesh generation
- **19_retopoflow_contours.feature** - RetopoFlow Contours tool
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_retopoflow.py`
- Cylindrical anatomy ring loops
- **20_retopoflow_polystrips.feature** - RetopoFlow PolyStrips tool
- Status: 3/3 passing
- Location: `tests/retopo_tools/test_retopoflow.py`
- Feature line loop control
- **21_retopoflow_strokes.feature** - RetopoFlow Strokes tool
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_retopoflow.py`
- Patch filling between loops
- **22_retopoflow_brushes.feature** - RetopoFlow Relax/Tweak brushes
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_retopoflow.py`
- On-demand smoothing and vertex adjustment
- **23_looptools_relax.feature** - LoopTools Relax operation
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_looptools.py`
- Vertex redistribution for even spacing
- **24_looptools_space.feature** - LoopTools Space operation
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_looptools.py`
- Equalize distance along loops
- **25_looptools_bridge_flatten.feature** - LoopTools Bridge and Flatten
- Status: 4/4 passing (2 scenarios: bridge + flatten)
- Location: `tests/retopo_tools/test_looptools.py`
- Gap filling and planarization
- **26_machin3_surface_slide.feature** - MACHIN3tools Surface Slide
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_machin3tools.py`
- Temporary on-surface editing with auto Shrinkwrap
- **27_quadwrap.feature** - QuadWrap cylindrical wrapping
- Status: 2/2 passing
- Location: `tests/retopo_tools/test_quadwrap.py`
- Automated ring loops for tube-like structures
**Summary of New Tests:**
- 27 new test scenarios across 12 new feature files
- 5 new test modules in tests/retopo_tools/
- All scenarios passing (100% success rate for new tests)
- Professional add-on integrations for LLM-driven retopology workflows
### Known Gaps
1. **XFAIL: Resource Registration** (tests/mcp/test_contract.py)
- MCP resources are not yet registered in the server
- Viewport screenshot is available as a tool but not as a resource
- This is a known architectural gap
2. **SKIPPED: Flipped Normals Detection** (tests/tools/test_mesh_analysis.py)
- Feature is specified but test implementation deferred
- Not a blocking issue
## Key Fixtures
### Test Infrastructure (`conftest.py`)
#### Connection Mocking
- `mock_blender_connection`: Simulates Blender addon socket connection
- `mock_server`: Provides mock MCP server instance
#### Sample Data
- `sample_mesh_stats`: Typical mesh statistics response
- `sample_topology_issues`: Topology issue detection response
- `sample_clean_topology`: Clean mesh validation response
#### Validators
- `tool_validator`: Validates MCP tool definitions
- `resource_validator`: Validates MCP resource definitions
- `prompt_validator`: Validates MCP prompt definitions
#### Helpers
- `mesh_factory`: Creates mock mesh data structures
- `error_simulator`: Simulates various error conditions
- `bdd_context`: Shared context for Given/When/Then steps
#### Hypothesis Strategies (Property-Based Testing)
- `mesh_stats_strategy`: Generate valid mesh statistics
- `angle_strategy`: Valid angle values (0-180°)
- `ratio_strategy`: Valid ratio values (0.0-1.0)
## Testing Heuristics
### MCP Contract Validation
**What to assert:**
- Tool definitions have required fields: name, description, inputSchema
- All parameters have defined types
- Resources declare correct MIME types
- Prompts provide meaningful guidance
**What NOT to assert:**
- Internal tool implementation details
- Specific function signatures
- Private module organization
### Mesh Analysis
**Key properties:**
- Vertex/edge/face counts must be non-negative integers
- Tris + quads + ngons should equal total faces
- Non-manifold detection is deterministic
- Sharp edge thresholds are inclusive (≥ angle)
**Invariants:**
- Clean mesh has no topology issues
- Issue detection suggests actionable fixes
### Remeshing (Voxel, QuadriFlow)
**Expected behaviors:**
- Smaller voxel size → higher face count
- Shape preservation within tolerance (~2-5% volume difference)
- QuadriFlow requires manifold mesh (precondition)
- Target face counts are approximate (±10% tolerance)
**Error conditions:**
- Non-manifold mesh → clear error message with fix suggestions
- Inconsistent normals → suggest "Recalculate Outside"
### Viewport and Camera
**State management:**
- Viewport projection independent of camera projection
- Aligning camera to view transfers viewport orientation
- Ortho scale "auto" calculates from scene bounds
**Rendering:**
- Final render uses **camera** projection, not viewport
- Batch ortho renders maintain consistent framing
### Baking
**Preconditions:**
- Low-poly mesh must have UV coordinates
- Error suggests "Unwrap UVs" or "Smart UV Project"
**Postconditions:**
- Image saved to //textures/ directory
- Material created and normal map connected
- Resolution matches requested map_size
### Safety
**Arbitrary code execution:**
- `execute_blender_code` requires `confirm=true`
- Without confirmation → rejected with safety message
- Error handling doesn't crash Blender
- Documentation explains risks
## Writing New Tests
### Step 1: Understand the Feature
Read the `.feature` file and extract:
- **Preconditions**: What state is required?
- **Actions**: What operations are performed?
- **Expected outcomes**: What should change? What invariants hold?
### Step 2: Derive Testing Heuristics
Document in test module docstring:
- Key behavioral properties to assert
- Invariants that must hold
- Preconditions and setup requirements
- Expected error conditions
- Edge cases and boundary conditions
### Step 3: Determine Test Location
Based on the mirrored structure:
- Testing MCP server contract? → `tests/mcp/`
- Testing a tool in `src/tools/`? → `tests/tools/`
- Testing implementation in `src/retopo_tools/`? → `tests/retopo_tools/`
- Testing prompts in `src/prompts/`? → `tests/prompts/`
### Step 4: Implement Given/When/Then Steps
```python
from pytest_bdd import scenarios, given, when, then, parsers
# Use relative path from test file to features directory
scenarios('../../features/my_feature.feature')
@given("precondition is met")
def setup_precondition(bdd_context):
"""Set up required state"""
bdd_context["state"] = "ready"
@when("I call the tool")
def call_tool(bdd_context, mock_blender_connection):
"""Execute the action"""
result = mock_blender_connection.send_command("tool_name", {})
bdd_context["result"] = result
@then("expected outcome occurs")
def verify_outcome(bdd_context):
"""Assert expected behavior"""
result = bdd_context["result"]
assert result["success"], "Operation should succeed"
```
### Step 5: Use Fixtures Effectively
```python
@given("a complex mesh")
def complex_mesh(bdd_context, mesh_factory):
"""Use factory fixtures for consistent test data"""
bdd_context["mesh"] = mesh_factory.create_high_poly(face_count=10000)
@when("I call the tool with invalid params")
def call_with_invalid_params(bdd_context, error_simulator):
"""Use error simulator for error conditions"""
result = error_simulator.invalid_params("Missing required field")
bdd_context["result"] = result
```
### Step 6: Mark Incomplete Features
```python
@then("feature X works correctly")
def feature_x_works(bdd_context):
"""Validate feature X"""
result = bdd_context["result"]
if not result["success"]:
pytest.xfail("Feature X not yet implemented")
assert result["success"], "Feature X should work"
```
## Property-Based Testing with Hypothesis
For testing input validation and invariants across wide ranges:
```python
from hypothesis import given, strategies as st
@given(st.floats(min_value=0.0, max_value=180.0))
def test_angle_threshold_property(angle):
"""Sharp edges detection should be monotonic with angle"""
# Lower angles should detect more or equal edges
pass
```
Use property-based tests for:
- Input validation across ranges
- Invariants that hold for all inputs
- Edge cases difficult to enumerate
- Stateful behavior verification
## Best Practices
### DO
- ✓ Test observable behaviors and properties
- ✓ Validate interface contracts (schemas, types, return structures)
- ✓ Check error messages and exception types
- ✓ Verify state transitions and invariants
- ✓ Use descriptive assertion messages
- ✓ Keep tests focused and single-purpose
- ✓ Document heuristics and expected behaviors
- ✓ Place tests in the appropriate directory mirroring `src/`
### DON'T
- ✗ Test private methods or internal details
- ✗ Create coupling between test and implementation
- ✗ Use arbitrary timeouts or sleep calls
- ✗ Depend on test execution order
- ✗ Modify production code from tests
- ✗ Assert on implementation-specific values
## Continuous Improvement
As features are implemented:
1. **Remove xfail markers** when features are complete
2. **Refactor tests** for better readability
3. **Extract reusable helpers** from duplicated code
4. **Add property-based tests** as invariants become clear
5. **Update documentation** to reflect current state
6. **Maintain mirrored structure** when adding new modules
## Debugging Test Failures
### View BDD step details
```bash
# See which step failed with full context
pytest tests/tools/test_mesh_analysis.py::test_detect_non_manifold_edges -vv
```
### Use pytest debugging
```python
# Add breakpoint in test
@then("expected outcome")
def verify_outcome(bdd_context):
import pdb; pdb.set_trace() # Debugger
assert ...
```
### Check mock responses
```python
@when("I call the tool")
def call_tool(bdd_context, mock_blender_connection):
result = mock_blender_connection.send_command("tool", {})
# Inspect last command sent
print(mock_blender_connection.last_command)
bdd_context["result"] = result
```
## Integration with CI/CD
### GitHub Actions Example
```yaml
name: Test Suite
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.10
- name: Install dependencies
run: |
pip install pytest pytest-bdd hypothesis
pip install -e .
- name: Run tests
run: pytest tests/ -v --tb=short
```
## Contact and Contribution
When adding new features:
1. Add corresponding `.feature` file to `features/`
2. Implement test module in appropriate `tests/` subdirectory (mirroring `src/`)
3. Update this README with coverage status
4. Ensure tests are deterministic and well-documented
For questions about test architecture or best practices, refer to:
- pytest-bdd documentation: https://pytest-bdd.readthedocs.io/
- Hypothesis documentation: https://hypothesis.readthedocs.io/
---
**Test Quality is Production Quality**
Every test in this suite should be:
- **Clear**: Easy to understand what is being tested
- **Purposeful**: Tests a specific behavior or property
- **Maintainable**: Easy to update as features evolve
- **Reliable**: Deterministic and isolated from external state
- **Well-organized**: Located in the correct directory mirroring source structure