QA Engineer Skills 2026QA-2026Schema Federation Testing

Schema Federation Testing

The Federation Challenge

When using Apollo Federation or schema stitching, multiple subgraph services contribute types and fields to a composed supergraph. Testing must verify that the composition is correct, that entity references resolve across subgraph boundaries, and that there are no conflicting type definitions.


Federation Architecture

+------------------+  +------------------+  +------------------+
| ProductService   |  | OrderService     |  | UserService      |
| Subgraph         |  | Subgraph         |  | Subgraph         |
|                  |  |                  |  |                  |
| type Product     |  | type Order       |  | type User        |
|   @key(id)       |  |   items: [Item]  |  |   @key(id)       |
|   name: String   |  |   customer: User |  |   name: String   |
|   price: Float   |  |                  |  |   email: String  |
+--------+---------+  +--------+---------+  +--------+---------+
         |                     |                     |
         +---------------------+---------------------+
                               |
                    +----------+----------+
                    |   Apollo Gateway    |
                    |   (Composed Schema) |
                    +---------------------+

Test 1: All Subgraph Types Are Resolvable

class TestSchemaFederation:
    """Test that federated GraphQL schemas compose correctly."""

    def test_all_subgraph_types_resolvable(self, composed_schema, subgraphs):
        """Every type defined in a subgraph should be resolvable
        in the composed schema."""
        for subgraph_name, subgraph_schema in subgraphs.items():
            for type_name in subgraph_schema.get_types():
                if type_name.startswith("__"):  # Skip introspection types
                    continue
                assert type_name in composed_schema.get_types(), (
                    f"Type '{type_name}' from subgraph '{subgraph_name}' "
                    f"is not resolvable in the composed schema"
                )

Test 2: Entity References Resolve Across Subgraphs

    def test_entity_references_resolve(self, gateway_client):
        """Entity references across subgraphs should resolve without errors."""
        # Product is defined in ProductService, but Order references it
        query = """
        query {
          order(id: "order-123") {
            id
            items {
              product {
                id
                name        # Resolved from ProductService
                price       # Resolved from ProductService
              }
              quantity
            }
          }
        }
        """
        response = gateway_client.execute(query)
        assert "errors" not in response, (
            f"Entity resolution failed: {response.get('errors')}"
        )
        assert response["data"]["order"]["items"][0]["product"]["name"] is not None

Test 3: No Conflicting Type Definitions

When two subgraphs extend the same type, their field definitions must be compatible:

    def test_no_conflicting_type_definitions(self, subgraphs):
        """Subgraphs should not define conflicting field types for shared types."""
        type_fields = {}
        conflicts = []

        for subgraph_name, schema in subgraphs.items():
            for type_name, type_def in schema.get_types().items():
                if type_name.startswith("__"):
                    continue
                if type_name not in type_fields:
                    type_fields[type_name] = {}
                for field_name, field_type in type_def.fields.items():
                    if field_name in type_fields[type_name]:
                        existing = type_fields[type_name][field_name]
                        if field_type != existing["type"]:
                            conflicts.append(
                                f"Field '{type_name}.{field_name}' has conflicting types: "
                                f"'{existing['type']}' in {existing['subgraph']} vs "
                                f"'{field_type}' in {subgraph_name}"
                            )
                    type_fields[type_name][field_name] = {
                        "type": field_type,
                        "subgraph": subgraph_name
                    }

        assert not conflicts, (
            f"Found {len(conflicts)} type conflicts:\n" + "\n".join(conflicts)
        )

Test 4: Subgraph Health and Availability

    def test_all_subgraphs_healthy(self, subgraph_endpoints):
        """Each subgraph should respond to health checks."""
        for name, url in subgraph_endpoints.items():
            response = httpx.get(f"{url}/.well-known/apollo/server-health")
            assert response.status_code == 200, (
                f"Subgraph '{name}' at {url} is unhealthy: {response.status_code}"
            )

    def test_gateway_introspection(self, gateway_client):
        """Gateway should respond to introspection queries."""
        query = """
        {
          __schema {
            types { name }
            queryType { name }
          }
        }
        """
        response = gateway_client.execute(query)
        assert "errors" not in response
        type_names = [t["name"] for t in response["data"]["__schema"]["types"]]
        # Verify key types from each subgraph are present
        assert "Product" in type_names
        assert "Order" in type_names
        assert "User" in type_names

Test 5: Cross-Subgraph Query Performance

    def test_cross_subgraph_query_latency(self, gateway_client):
        """Queries spanning multiple subgraphs should meet latency SLA."""
        # This query touches all three subgraphs
        query = """
        query {
          user(id: "user-1") {
            name                          # UserService
            orders(first: 5) {            # OrderService
              id
              total
              items {
                product {
                  name                    # ProductService
                  price
                }
              }
            }
          }
        }
        """
        import time
        start = time.monotonic()
        response = gateway_client.execute(query)
        duration = time.monotonic() - start

        assert "errors" not in response
        assert duration < 3.0, (
            f"Cross-subgraph query took {duration:.2f}s, SLA is 3.0s. "
            f"Check query plan and subgraph latencies."
        )

AI-Generated Federation Tests

Ask AI to generate federation tests from your subgraph schemas:

Given the following Apollo Federation subgraph schemas, generate tests
that verify correct composition:

Subgraph 1 (ProductService):
type Product @key(fields: "id") {
  id: ID!
  name: String!
  price: Float!
  category: Category!
}

Subgraph 2 (InventoryService):
extend type Product @key(fields: "id") {
  id: ID! @external
  inStock: Boolean!
  warehouseLocation: String
}

Subgraph 3 (ReviewService):
extend type Product @key(fields: "id") {
  id: ID! @external
  reviews: [Review!]!
  averageRating: Float
}

Generate tests for:
1. Each subgraph's fields resolve correctly through the gateway
2. Cross-subgraph queries work (e.g., product with stock AND reviews)
3. Entity reference resolution (no null references)
4. Performance: cross-subgraph queries under 2s
5. Error handling: what happens when one subgraph is down?

Graceful Degradation Testing

    def test_gateway_handles_subgraph_failure(self, gateway_client, subgraph_controller):
        """Gateway should return partial data when one subgraph is down."""
        # Stop the ReviewService subgraph
        subgraph_controller.stop("ReviewService")

        query = """
        query {
          product(id: "prod-1") {
            name          # From ProductService (available)
            price         # From ProductService (available)
            reviews {     # From ReviewService (unavailable)
              rating
            }
          }
        }
        """
        response = gateway_client.execute(query)

        # Product data should still be available
        assert response["data"]["product"]["name"] is not None
        assert response["data"]["product"]["price"] is not None

        # Reviews should be null or have an error
        assert (
            response["data"]["product"]["reviews"] is None
            or "errors" in response
        )

        # Restart for other tests
        subgraph_controller.start("ReviewService")

Key Takeaway

Federation testing verifies that independently-developed subgraphs compose correctly into a functioning supergraph. The critical tests are: type resolution across subgraph boundaries, conflict detection between shared types, cross-subgraph query performance, and graceful degradation when a subgraph fails. AI can generate these tests from subgraph SDL schemas, covering composition correctness and entity reference resolution systematically.