# Test Migration Example: test_provider.py

## Original Test (BAD)

```python
# From tests/unit/test_provider.py
def test_find_instances(self, provider):
    """Test finding available instances."""
    # Setup mock response
    mock_instances = [
        AvailableInstance(
            allocation_id="alloc-123",
            instance_type="a100.80gb.sxm4.1x",
            region="us-central1-a",
            price_per_hour=25.60
        )
    ]
    provider.compute.find_instances.return_value = mock_instances
    
    instances = provider.compute.find_instances(
        instance_types=["a100.80gb.sxm4.1x"],
        regions=["us-central1-a"]
    )
    
    assert len(instances) == 1
    assert instances[0].allocation_id == "alloc-123"
    assert instances[0].price_per_hour == 25.60
```

### Problems:
1. **Tests the mock, not the code** - Just verifies mock.return_value
2. **Hardcoded values** - "alloc-123", 25.60
3. **No behavior testing** - Doesn't test parsing, error handling, or logic
4. **Zero value** - Could delete this test and lose nothing

## Migrated Test (GOOD)

### Option 1: Unit Test (Test Our Logic)

```python
# tests/unit/test_fcp_provider_unit.py
class TestFCPProviderFindInstances:
    """Test our find_instances implementation logic."""
    
    def test_parse_auction_response_to_instances(self):
        """Test that we correctly parse FCP auction responses."""
        # Create provider with mocked HTTP client ONLY
        config = Config(provider="fcp", auth_token="test")
        mock_http = Mock()
        provider = FCPProvider(config, http_client=mock_http)
        
        # Mock the HTTP response (not the provider!)
        mock_http.get.return_value = {
            "auctions": [
                {
                    "auction_id": "auc-abc123",
                    "instance_type": {
                        "id": "a100-80gb",
                        "name": "NVIDIA A100 80GB"
                    },
                    "zones": [{"zone_id": "us-east-1a", "available": 5}],
                    "current_price": 24.50,
                    "limit_price": 30.00
                },
                {
                    "auction_id": "auc-def456",
                    "instance_type": {
                        "id": "a100-80gb",
                        "name": "NVIDIA A100 80GB"
                    },
                    "zones": [{"zone_id": "us-west-2a", "available": 2}],
                    "current_price": 26.00,
                    "limit_price": 30.00
                }
            ]
        }
        
        # Test OUR parsing logic
        instances = provider.find_instances({
            "instance_type": "a100-80gb",
            "max_price_per_hour": 30.0
        })
        
        # Verify we parse correctly
        assert len(instances) == 2
        assert all(i.instance_type == "a100-80gb" for i in instances)
        assert all(i.price_per_hour <= 30.0 for i in instances)
        # Verify sorting by price
        assert instances[0].price_per_hour <= instances[1].price_per_hour
    
    @pytest.mark.parametrize("requirements,expected_params", [
        (
            {"instance_type": "a100", "max_price": 50},
            {"instance_type_id": "a100-80gb", "max_price": 50}
        ),
        (
            {"instance_type": "h100-80gb", "region": "us-east-1"},
            {"instance_type_id": "h100-80gb", "zones": ["us-east-1a", "us-east-1b"]}
        ),
    ])
    def test_requirement_translation(self, requirements, expected_params):
        """Test that we translate requirements to API parameters correctly."""
        config = Config(provider="fcp", auth_token="test")
        mock_http = Mock()
        provider = FCPProvider(config, http_client=mock_http)
        
        # Mock empty response
        mock_http.get.return_value = {"auctions": []}
        
        # Call method
        provider.find_instances(requirements)
        
        # Verify we called API with correct parameters
        call_args = mock_http.get.call_args
        for key, value in expected_params.items():
            assert call_args[1]["params"][key] == value
```

### Option 2: Integration Test (Test Real Behavior)

```python
# tests/integration/test_fcp_integration.py
@pytest.mark.integration
class TestFCPFindInstancesIntegration:
    """Test find_instances against real API."""
    
    @pytest.fixture
    def real_provider(self):
        """Real provider with test credentials."""
        return create_test_provider()
    
    def test_find_gpu_instances_real(self, real_provider):
        """Test finding real GPU instances."""
        # Use real API
        instances = real_provider.find_instances({
            "instance_type": "a100-80gb",
            "max_price_per_hour": 100.0  # High limit for test
        }, limit=5)
        
        # Verify real data
        if instances:  # May be empty if none available
            for instance in instances:
                # Real instance IDs are UUIDs
                assert len(instance.allocation_id) > 10
                # Real prices are positive
                assert instance.price_per_hour > 0
                # Real regions follow pattern
                assert instance.region in VALID_REGIONS
                # Price respects our limit
                assert instance.price_per_hour <= 100.0
    
    @pytest.mark.parametrize("instance_type", [
        "a100-40gb",
        "a100-80gb", 
        "h100-80gb",
        "v100-16gb",
        "cpu-small",
        "cpu-large"
    ])
    def test_instance_type_availability(self, real_provider, instance_type):
        """Test that advertised instance types are queryable."""
        # This is a CONTRACT test - verifies API compatibility
        try:
            instances = real_provider.find_instances({
                "instance_type": instance_type
            }, limit=1)
            # Should not error
        except ValidationError as e:
            pytest.fail(f"Instance type {instance_type} not recognized: {e}")
```

## Key Differences

### Bad Test
- Tests mock behavior
- Hardcoded fake data
- No error cases
- No real validation

### Good Unit Test  
- Tests OUR parsing logic
- Tests OUR parameter translation
- Tests OUR error handling
- Mocks only HTTP boundary

### Good Integration Test
- Tests against REAL API
- Verifies REAL behavior
- Tests API contract
- No mocks at all

## Migration Steps

1. **Identify what's being tested**
   - Is it testing our logic? → Unit test with HTTP mocking
   - Is it testing integration? → Integration test with real API

2. **Remove all provider mocking**
   - Never mock the class under test
   - Mock only external boundaries (HTTP, filesystem)

3. **Replace hardcoded data with:**
   - Builders for test input
   - Assertions on behavior, not exact values
   - Parameterized tests for variants

4. **Add error cases**
   - Network failures
   - Invalid responses  
   - API errors

5. **Add contract tests**
   - Verify our assumptions about the API
   - Run against real system