Backend Testing - 2/2

From Unit Testing to Production Confidence

You’ve mastered testing fundamentals with strategic test pyramids that balance speed and coverage, comprehensive unit tests that validate business logic and edge cases, integration tests that ensure components work together reliably, and sophisticated mocking strategies that enable testing without external dependencies. Your test suites catch bugs early and prevent regressions through isolated, fast-running validation. But here’s the production reality that separates tested code from bulletproof systems: even with perfect unit tests, flawless integration tests, and comprehensive mocks, your application is vulnerable if it can’t handle real user loads, API contract changes, or the chaotic conditions of production environments.

The production testing gap that destroys user experience:

// Your perfectly unit-tested API that crumbles under real-world conditions
app.post(
  "/api/orders",
  validateOrderInput,
  authenticateUser,
  async (req, res) => {
    try {
      // Unit tests pass: ✅ Business logic works
      // Integration tests pass: ✅ Database operations work
      // Mocks work perfectly: ✅ External services mocked

      const order = await processOrder(req.body);
      const payment = await processPayment(order.total);
      const shipment = await scheduleShipment(order.items);

      res.json({ success: true, orderId: order.id });

      // Hidden problems that only show up in production:
      // - API response time: 8 seconds under normal load (users abandon)
      // - Memory leak: 50MB per order processing (server crashes after 100 orders)
      // - Database connection pool exhaustion after 20 concurrent requests
      // - Payment API rate limits cause 429 errors during peak hours
      // - Shipping API contract changed: new required fields break integration
      // - Error responses don't match API documentation
      // - CORS headers missing for frontend integration
      // - Request size limits cause 413 errors for large orders
    } catch (error) {
      res.status(500).json({ error: "Order processing failed" });
    }
  }
);

// The production reality check that unit tests miss:
// - "It works on my machine" but fails in staging
// - Performance degrades exponentially under load
// - APIs break when external services update
// - Error scenarios that only happen with real user patterns
// - Integration failures that mocks can't simulate

The uncomfortable production truth: Comprehensive unit and integration tests mean nothing if your APIs can’t handle real user loads, if performance degrades under pressure, or if external service changes break your integrations. Modern applications require testing strategies that validate not just correctness, but performance, resilience, and real-world integration scenarios.

Real-world production testing failure consequences:

// What happens when production testing is incomplete:
const productionTestingFailureImpact = {
  performanceCollapse: {
    problem:
      "API response times increase from 200ms to 8+ seconds during flash sale",
    cause: "No load testing revealed database query N+1 problem",
    impact: "87% of users abandon checkout, $1.3M in lost sales",
    discovery: "Customers complained on social media during peak traffic",
    solution: "Emergency database query optimization and connection pooling",
  },

  integrationBreakage: {
    problem: "Payment processing fails after Stripe API v2023-10 update",
    cause: "API contract tests not automated, breaking changes undetected",
    impact: "4 hours of failed payments, 2,847 angry customers",
    emergency: "Manual rollback to previous API version",
    reputation: "Payment reliability concerns lead to 18% customer churn",
  },

  cascadingFailure: {
    problem: "Recommendation service timeout brings down entire product page",
    cause: "No circuit breaker testing, timeouts not properly configured",
    impact: "Complete site outage for 2.5 hours during prime shopping hours",
    scope: "Affected all product pages, search, and checkout flow",
    cost: "$420K in lost revenue + emergency incident response",
  },

  // Perfect unit tests are meaningless when real-world conditions
  // reveal performance bottlenecks and integration vulnerabilities
};

Advanced backend testing mastery requires understanding:

  • API testing (automated and manual) that validates contracts, error scenarios, and real-world integration patterns
  • Load testing and performance testing that reveals bottlenecks before users encounter them
  • Test-driven development (TDD) that designs better code through testing-first approaches
  • Continuous testing practices that integrate quality gates into deployment pipelines
  • Testing environments and data that mirror production conditions accurately

This article completes your testing education by building production-ready testing strategies. You’ll create API test suites that catch breaking changes, performance tests that reveal bottlenecks, TDD workflows that improve code design, and continuous testing pipelines that prevent regressions from reaching users.


API Testing: Contract Validation and Integration Assurance

Comprehensive API Testing Strategy

The API testing approach that catches integration issues early:

// ✅ Professional API testing with contract validation and error scenario coverage
// tests/api/UserAPI.test.js
describe("User API Integration Tests", () => {
  let app;
  let server;
  let testDb;

  beforeAll(async () => {
    // Setup test environment
    testDb = await createTestDatabase();
    app = createApp({ database: testDb, environment: "test" });
    server = app.listen(0); // Random available port
  });

  afterAll(async () => {
    await server.close();
    await testDb.cleanup();
  });

  beforeEach(async () => {
    // Clean test data
    await testDb.users.deleteMany({});
    await testDb.sessions.deleteMany({});
  });

  describe("POST /api/users/register", () => {
    const validUserData = {
      email: "test@example.com",
      password: "SecurePass123!",
      firstName: "John",
      lastName: "Doe",
    };

    describe("Success Scenarios", () => {
      it("creates user with valid data and returns expected structure", async () => {
        // Act
        const response = await request(app)
          .post("/api/users/register")
          .send(validUserData)
          .expect("Content-Type", /json/)
          .expect(201);

        // Assert response structure matches API contract
        expect(response.body).toMatchSchema({
          type: "object",
          required: ["success", "message", "userId", "user"],
          properties: {
            success: { type: "boolean", enum: [true] },
            message: { type: "string" },
            userId: { type: "string", format: "uuid" },
            user: {
              type: "object",
              required: ["id", "email", "firstName", "lastName", "createdAt"],
              properties: {
                id: { type: "string" },
                email: { type: "string", format: "email" },
                firstName: { type: "string" },
                lastName: { type: "string" },
                createdAt: { type: "string", format: "date-time" },
                // Password should never be in response
                password: { not: {} },
              },
            },
          },
        });

        // Verify actual user creation
        const createdUser = await testDb.users.findOne({
          email: validUserData.email,
        });
        expect(createdUser).toBeDefined();
        expect(createdUser.emailVerified).toBe(false);
      });

      it("handles international characters in names correctly", async () => {
        const internationalUserData = {
          ...validUserData,
          firstName: "José",
          lastName: "Müller-García",
          email: "josé.müller@example.com",
        };

        const response = await request(app)
          .post("/api/users/register")
          .send(internationalUserData)
          .expect(201);

        expect(response.body.user.firstName).toBe("José");
        expect(response.body.user.lastName).toBe("Müller-García");

        // Verify database stores UTF-8 correctly
        const dbUser = await testDb.users.findOne({
          email: internationalUserData.email,
        });
        expect(dbUser.firstName).toBe("José");
      });
    });

    describe("Validation Error Scenarios", () => {
      it("returns 400 for missing required fields", async () => {
        const incompleteData = { email: "test@example.com" };

        const response = await request(app)
          .post("/api/users/register")
          .send(incompleteData)
          .expect("Content-Type", /json/)
          .expect(400);

        expect(response.body).toMatchSchema({
          type: "object",
          required: ["error", "message", "validationErrors"],
          properties: {
            error: { type: "string" },
            message: { type: "string" },
            validationErrors: {
              type: "array",
              items: {
                type: "object",
                required: ["field", "message"],
                properties: {
                  field: { type: "string" },
                  message: { type: "string" },
                },
              },
            },
          },
        });

        // Verify specific validation errors
        const errors = response.body.validationErrors;
        const missingFields = errors.map((e) => e.field);
        expect(missingFields).toContain("password");
        expect(missingFields).toContain("firstName");
        expect(missingFields).toContain("lastName");
      });

      it("returns 400 for invalid email format", async () => {
        const invalidEmailData = {
          ...validUserData,
          email: "not-an-email",
        };

        const response = await request(app)
          .post("/api/users/register")
          .send(invalidEmailData)
          .expect(400);

        const emailError = response.body.validationErrors.find(
          (e) => e.field === "email"
        );
        expect(emailError.message).toMatch(/valid email/i);
      });

      it("returns 400 for weak password", async () => {
        const weakPasswordData = {
          ...validUserData,
          password: "123",
        };

        const response = await request(app)
          .post("/api/users/register")
          .send(weakPasswordData)
          .expect(400);

        const passwordError = response.body.validationErrors.find(
          (e) => e.field === "password"
        );
        expect(passwordError.message).toMatch(/password requirements/i);
      });
    });

    describe("Conflict Scenarios", () => {
      it("returns 409 for duplicate email registration", async () => {
        // Create existing user
        await testDb.users.insertOne({
          id: "existing123",
          email: validUserData.email,
          hashedPassword: "hashed123",
        });

        const response = await request(app)
          .post("/api/users/register")
          .send(validUserData)
          .expect("Content-Type", /json/)
          .expect(409);

        expect(response.body).toMatchObject({
          error: "Email already registered",
          message: expect.stringMatching(/account.*already exists/i),
        });
      });
    });

    describe("Rate Limiting", () => {
      it("enforces rate limits for registration attempts", async () => {
        const rateLimitRequests = [];

        // Send multiple requests rapidly
        for (let i = 0; i < 10; i++) {
          const userData = {
            ...validUserData,
            email: `test${i}@example.com`,
          };

          rateLimitRequests.push(
            request(app).post("/api/users/register").send(userData)
          );
        }

        const responses = await Promise.all(rateLimitRequests);

        // Some requests should be rate limited
        const rateLimitedResponses = responses.filter((r) => r.status === 429);
        expect(rateLimitedResponses.length).toBeGreaterThan(0);

        // Rate limit response should include retry headers
        const rateLimitResponse = rateLimitedResponses[0];
        expect(rateLimitResponse.headers["retry-after"]).toBeDefined();
        expect(rateLimitResponse.body.error).toMatch(/rate limit/i);
      });
    });
  });

  describe("GET /api/users/profile", () => {
    let authenticatedUser;
    let authToken;

    beforeEach(async () => {
      // Create authenticated user for protected endpoint testing
      authenticatedUser = await testDb.users.insertOne({
        id: "user123",
        email: "auth@example.com",
        firstName: "Auth",
        lastName: "User",
        emailVerified: true,
      });

      // Create auth token/session
      const response = await request(app).post("/api/auth/login").send({
        email: "auth@example.com",
        password: "TestPassword123!",
      });

      authToken = response.body.token;
    });

    describe("Authentication Tests", () => {
      it("returns user profile for authenticated request", async () => {
        const response = await request(app)
          .get("/api/users/profile")
          .set("Authorization", `Bearer ${authToken}`)
          .expect("Content-Type", /json/)
          .expect(200);

        expect(response.body).toMatchSchema({
          type: "object",
          required: ["user"],
          properties: {
            user: {
              type: "object",
              required: ["id", "email", "firstName", "lastName"],
              properties: {
                id: { type: "string" },
                email: { type: "string" },
                firstName: { type: "string" },
                lastName: { type: "string" },
                // Sensitive fields should not be included
                password: { not: {} },
                hashedPassword: { not: {} },
              },
            },
          },
        });
      });

      it("returns 401 for missing authentication", async () => {
        const response = await request(app)
          .get("/api/users/profile")
          .expect("Content-Type", /json/)
          .expect(401);

        expect(response.body).toMatchObject({
          error: "Authentication required",
          message: expect.any(String),
        });
      });

      it("returns 401 for invalid token", async () => {
        const response = await request(app)
          .get("/api/users/profile")
          .set("Authorization", "Bearer invalid-token")
          .expect(401);

        expect(response.body.error).toMatch(/invalid.*token/i);
      });

      it("returns 401 for expired token", async () => {
        // Create expired token
        const expiredToken = jwt.sign(
          { userId: "user123" },
          process.env.JWT_SECRET,
          { expiresIn: "-1h" }
        );

        const response = await request(app)
          .get("/api/users/profile")
          .set("Authorization", `Bearer ${expiredToken}`)
          .expect(401);

        expect(response.body.error).toMatch(/expired/i);
      });
    });
  });

  describe("API Contract Compliance", () => {
    it("includes required CORS headers", async () => {
      const response = await request(app)
        .options("/api/users/register")
        .set("Origin", "https://frontend.example.com")
        .set("Access-Control-Request-Method", "POST")
        .expect(200);

      expect(response.headers["access-control-allow-origin"]).toBe("*");
      expect(response.headers["access-control-allow-methods"]).toContain(
        "POST"
      );
      expect(response.headers["access-control-allow-headers"]).toContain(
        "Content-Type"
      );
    });

    it("includes security headers", async () => {
      const response = await request(app).get("/api/health").expect(200);

      expect(response.headers["x-content-type-options"]).toBe("nosniff");
      expect(response.headers["x-frame-options"]).toBe("DENY");
      expect(response.headers["x-xss-protection"]).toBe("1; mode=block");
    });

    it("handles request size limits appropriately", async () => {
      const oversizedData = {
        email: "test@example.com",
        password: "SecurePass123!",
        firstName: "x".repeat(10000), // Oversized field
        lastName: "Doe",
      };

      const response = await request(app)
        .post("/api/users/register")
        .send(oversizedData)
        .expect(413); // Payload too large

      expect(response.body.error).toMatch(/payload.*large|request.*size/i);
    });

    it("returns consistent error format across all endpoints", async () => {
      // Test multiple error scenarios to ensure consistent format
      const errorResponses = await Promise.all([
        request(app).post("/api/users/register").send({}), // Validation error
        request(app).get("/api/users/profile"), // Auth error
        request(app).get("/api/nonexistent"), // Not found error
      ]);

      // All error responses should have consistent structure
      errorResponses.forEach((response) => {
        expect(response.body).toHaveProperty("error");
        expect(response.body).toHaveProperty("message");
        expect(typeof response.body.error).toBe("string");
        expect(typeof response.body.message).toBe("string");
      });
    });
  });
});

// Contract testing with external API dependencies
describe("External API Contract Tests", () => {
  describe("Payment Service Integration", () => {
    let mockPaymentServer;

    beforeAll(async () => {
      // Setup mock payment service that mimics real API
      mockPaymentServer = await createMockPaymentAPI();
    });

    afterAll(async () => {
      await mockPaymentServer.close();
    });

    it("handles payment service API changes gracefully", async () => {
      // Simulate API contract change
      mockPaymentServer.updateAPIVersion("2023-10-16");

      const paymentRequest = {
        amount: 2000,
        currency: "usd",
        source: "tok_visa",
        description: "Test payment",
      };

      try {
        const response = await paymentService.processPayment(paymentRequest);

        // Verify response matches expected contract
        expect(response).toMatchSchema(PAYMENT_RESPONSE_SCHEMA);
      } catch (error) {
        // If API change breaks our integration, test should document the issue
        expect(error.message).toMatch(/payment api/i);
        console.warn("Payment API contract change detected:", error.message);
      }
    });

    it("handles payment service timeouts appropriately", async () => {
      // Configure mock to simulate slow response
      mockPaymentServer.setResponseDelay(5000);

      const paymentRequest = {
        amount: 1000,
        currency: "usd",
        source: "tok_visa",
      };

      // Should timeout and handle gracefully
      await expect(
        paymentService.processPayment(paymentRequest)
      ).rejects.toThrow(/timeout/i);

      // Verify proper timeout handling
      const timeoutStart = Date.now();
      try {
        await paymentService.processPayment(paymentRequest);
      } catch (error) {
        const timeoutDuration = Date.now() - timeoutStart;
        expect(timeoutDuration).toBeLessThan(4000); // Should timeout before 4s
      }
    });
  });
});

Load Testing and Performance Testing: Scalability Validation

Professional Performance Testing Strategy

Load testing that reveals bottlenecks before users encounter them:

// ✅ Comprehensive performance testing with k6 and custom metrics
// performance/load-tests/api-load-test.js
import http from "k6/http";
import { check, sleep } from "k6";
import { Rate, Counter, Trend } from "k6/metrics";

// Custom metrics for detailed performance tracking
const errorRate = new Rate("error_rate");
const apiCalls = new Counter("api_calls_total");
const responseTimeP95 = new Trend("response_time_p95");
const databaseConnections = new Trend("database_connections");
const memoryUsage = new Trend("memory_usage_mb");

// Load testing configuration
export let options = {
  stages: [
    { duration: "2m", target: 10 }, // Ramp up to 10 users over 2 minutes
    { duration: "5m", target: 10 }, // Stay at 10 users for 5 minutes
    { duration: "2m", target: 50 }, // Ramp up to 50 users over 2 minutes
    { duration: "5m", target: 50 }, // Stay at 50 users for 5 minutes
    { duration: "2m", target: 100 }, // Ramp up to 100 users over 2 minutes
    { duration: "10m", target: 100 }, // Stay at 100 users for 10 minutes
    { duration: "5m", target: 200 }, // Spike to 200 users
    { duration: "2m", target: 0 }, // Ramp down to 0 users
  ],

  thresholds: {
    // Performance requirements
    http_req_duration: ["p(95)<500"], // 95% of requests must complete under 500ms
    http_req_failed: ["rate<0.01"], // Error rate must be less than 1%

    // Custom thresholds
    error_rate: ["rate<0.01"],
    response_time_p95: ["p(95)<500"],

    // Infrastructure thresholds
    database_connections: ["p(95)<80"], // DB connection pool limit
    memory_usage_mb: ["p(95)<512"], // Memory usage limit
  },

  // Test environment configuration
  ext: {
    loadimpact: {
      projectID: parseInt(__ENV.K6_PROJECT_ID || "0"),
      name: "API Load Test",
    },
  },
};

// Test data setup
const BASE_URL = __ENV.BASE_URL || "http://localhost:3000";
const API_KEY = __ENV.API_KEY || "test-api-key";

// User authentication pool for realistic testing
const userPool = [
  { email: "user1@example.com", password: "TestPass123!" },
  { email: "user2@example.com", password: "TestPass123!" },
  { email: "user3@example.com", password: "TestPass123!" },
  // ... more test users
];

// Authentication helper
function authenticate(user) {
  const loginResponse = http.post(
    `${BASE_URL}/api/auth/login`,
    JSON.stringify({
      email: user.email,
      password: user.password,
    }),
    {
      headers: {
        "Content-Type": "application/json",
      },
    }
  );

  check(loginResponse, {
    "login successful": (r) => r.status === 200,
    "login returns token": (r) => r.json("token") !== undefined,
  });

  return loginResponse.json("token");
}

// Main test scenario
export default function () {
  // Select random user for this iteration
  const user = userPool[Math.floor(Math.random() * userPool.length)];
  const token = authenticate(user);

  if (!token) {
    errorRate.add(1);
    return;
  }

  // Test scenario 1: User profile operations
  testUserProfile(token);
  sleep(1); // Think time between operations

  // Test scenario 2: Order creation workflow
  testOrderCreation(token);
  sleep(1);

  // Test scenario 3: Data retrieval operations
  testDataRetrieval(token);
  sleep(1);

  // Collect custom metrics
  collectSystemMetrics();
}

function testUserProfile(token) {
  const headers = {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  };

  // Get user profile
  const profileResponse = http.get(`${BASE_URL}/api/users/profile`, {
    headers,
  });

  const profileChecks = check(profileResponse, {
    "profile fetch successful": (r) => r.status === 200,
    "profile response time acceptable": (r) => r.timings.duration < 200,
    "profile contains required fields": (r) => {
      const profile = r.json("user");
      return profile && profile.id && profile.email;
    },
  });

  if (!profileChecks) {
    errorRate.add(1);
  }

  apiCalls.add(1);
  responseTimeP95.add(profileResponse.timings.duration);

  // Update profile
  const updateData = {
    firstName: `TestUser${Math.floor(Math.random() * 1000)}`,
    bio: "Updated bio from load test",
  };

  const updateResponse = http.put(
    `${BASE_URL}/api/users/profile`,
    JSON.stringify(updateData),
    { headers }
  );

  check(updateResponse, {
    "profile update successful": (r) => r.status === 200,
    "profile update response time acceptable": (r) => r.timings.duration < 300,
  });

  apiCalls.add(1);
}

function testOrderCreation(token) {
  const headers = {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  };

  // Simulate realistic order data
  const orderData = {
    items: [
      {
        productId: `product_${Math.floor(Math.random() * 100)}`,
        quantity: Math.floor(Math.random() * 5) + 1,
        price: Math.floor(Math.random() * 10000) + 1000,
      },
    ],
    shippingAddress: {
      street: "123 Test Street",
      city: "Test City",
      zipCode: "12345",
      country: "US",
    },
    paymentMethod: "card_test_token",
  };

  const orderResponse = http.post(
    `${BASE_URL}/api/orders`,
    JSON.stringify(orderData),
    { headers }
  );

  const orderChecks = check(orderResponse, {
    "order creation successful": (r) => r.status === 201,
    "order creation response time acceptable": (r) => r.timings.duration < 1000,
    "order response contains orderId": (r) => r.json("orderId") !== undefined,
    "order total calculated correctly": (r) => {
      const order = r.json();
      return order.total && order.total > 0;
    },
  });

  if (!orderChecks) {
    errorRate.add(1);
  }

  apiCalls.add(1);
  responseTimeP95.add(orderResponse.timings.duration);

  // Follow up with order status check
  if (orderResponse.status === 201) {
    const orderId = orderResponse.json("orderId");
    sleep(0.5); // Small delay before status check

    const statusResponse = http.get(`${BASE_URL}/api/orders/${orderId}`, {
      headers,
    });

    check(statusResponse, {
      "order status fetch successful": (r) => r.status === 200,
      "order status response time acceptable": (r) => r.timings.duration < 200,
    });

    apiCalls.add(1);
  }
}

function testDataRetrieval(token) {
  const headers = {
    Authorization: `Bearer ${token}`,
  };

  // Test search functionality with various queries
  const searchQueries = [
    { q: "test", limit: 20 },
    { q: "product", category: "electronics", limit: 10 },
    { sort: "created_at", order: "desc", limit: 50 },
  ];

  const query = searchQueries[Math.floor(Math.random() * searchQueries.length)];
  const queryString = Object.keys(query)
    .map((key) => `${key}=${encodeURIComponent(query[key])}`)
    .join("&");

  const searchResponse = http.get(`${BASE_URL}/api/search?${queryString}`, {
    headers,
  });

  check(searchResponse, {
    "search successful": (r) => r.status === 200,
    "search response time acceptable": (r) => r.timings.duration < 500,
    "search returns results array": (r) => Array.isArray(r.json("results")),
    "search includes pagination": (r) => {
      const data = r.json();
      return data.total !== undefined && data.page !== undefined;
    },
  });

  apiCalls.add(1);
  responseTimeP95.add(searchResponse.timings.duration);
}

function collectSystemMetrics() {
  // In a real scenario, you'd collect these from your monitoring system
  // This is a simplified example

  // Simulate database connection count (would come from monitoring API)
  const dbConnections = Math.floor(Math.random() * 20) + 40;
  databaseConnections.add(dbConnections);

  // Simulate memory usage (would come from monitoring API)
  const memUsage = Math.floor(Math.random() * 100) + 200;
  memoryUsage.add(memUsage);
}

// Stress testing scenario for peak load conditions
export function stressTest() {
  // This runs when k6 is started with --config stress-test.json
  const stressUser = userPool[0];
  const token = authenticate(stressUser);

  if (!token) return;

  // Rapid-fire requests to test system limits
  for (let i = 0; i < 5; i++) {
    const response = http.get(`${BASE_URL}/api/health`, {
      headers: { Authorization: `Bearer ${token}` },
    });

    check(response, {
      "stress test request successful": (r) => r.status === 200,
      "stress test response under 1s": (r) => r.timings.duration < 1000,
    });

    sleep(0.1); // Very short think time for stress testing
  }
}

// Performance test teardown
export function teardown(data) {
  // Cleanup test data if needed
  console.log("Load test completed");
  console.log(`Total API calls: ${apiCalls.value}`);
  console.log(`Error rate: ${(errorRate.value * 100).toFixed(2)}%`);
}

Database performance testing for query optimization:

// ✅ Database performance testing and query optimization validation
// performance/database-performance.test.js
describe("Database Performance Tests", () => {
  let db;
  let performanceMonitor;

  beforeAll(async () => {
    db = await connectToTestDatabase();
    performanceMonitor = new DatabasePerformanceMonitor(db);
  });

  afterAll(async () => {
    await db.close();
  });

  describe("Query Performance Benchmarks", () => {
    beforeAll(async () => {
      // Setup realistic test data volumes
      await seedLargeDataset();
    });

    it("user search queries perform under acceptable limits", async () => {
      const testQueries = [
        { email: "test@example.com" },
        { firstName: "John", lastName: "Doe" },
        { department: "Engineering" },
        { role: "Developer", isActive: true },
        { createdAt: { $gte: new Date("2023-01-01") } },
      ];

      for (const query of testQueries) {
        const startTime = process.hrtime.bigint();

        const results = await db.users.find(query).limit(20).toArray();

        const endTime = process.hrtime.bigint();
        const durationMs = Number(endTime - startTime) / 1000000;

        // Performance assertion
        expect(durationMs).toBeLessThan(100); // Under 100ms
        expect(results.length).toBeLessThanOrEqual(20);

        console.log(
          `Query ${JSON.stringify(query)}: ${durationMs.toFixed(2)}ms`
        );
      }
    });

    it("prevents N+1 query problems in user with orders retrieval", async () => {
      const queryCountBefore = await performanceMonitor.getQueryCount();

      // Fetch users with their orders (potential N+1 problem)
      const usersWithOrders = await db.users
        .aggregate([
          { $match: { isActive: true } },
          { $limit: 10 },
          {
            $lookup: {
              from: "orders",
              localField: "id",
              foreignField: "userId",
              as: "orders",
            },
          },
        ])
        .toArray();

      const queryCountAfter = await performanceMonitor.getQueryCount();
      const queriesExecuted = queryCountAfter - queryCountBefore;

      // Should be 1 aggregation query, not 1 + N individual queries
      expect(queriesExecuted).toBeLessThanOrEqual(2); // Allow for connection overhead
      expect(usersWithOrders).toHaveLength(10);
      expect(usersWithOrders[0].orders).toBeDefined();
    });

    it("handles large result set pagination efficiently", async () => {
      const pageSize = 50;
      const totalPages = 10;

      for (let page = 0; page < totalPages; page++) {
        const startTime = process.hrtime.bigint();

        const results = await db.users
          .find({})
          .sort({ createdAt: -1 })
          .skip(page * pageSize)
          .limit(pageSize)
          .toArray();

        const endTime = process.hrtime.bigint();
        const durationMs = Number(endTime - startTime) / 1000000;

        // Performance should not degrade significantly with offset
        expect(durationMs).toBeLessThan(150); // Allow slight increase for later pages
        expect(results.length).toBeLessThanOrEqual(pageSize);

        console.log(`Page ${page + 1}: ${durationMs.toFixed(2)}ms`);
      }
    });

    it("index usage is optimal for common queries", async () => {
      const commonQueries = [
        { email: "test@example.com" },
        { department: "Engineering", role: "Developer" },
        { isActive: true, createdAt: { $gte: new Date("2023-01-01") } },
      ];

      for (const query of commonQueries) {
        // Use explain to check index usage
        const explanation = await db.users
          .find(query)
          .explain("executionStats");

        // Verify index was used (not collection scan)
        expect(explanation.executionStats.executionSuccess).toBe(true);
        expect(explanation.executionStats.totalExamined).toBeLessThanOrEqual(
          explanation.executionStats.totalReturned * 2
        ); // Reasonable selectivity

        // Check for collection scan (should be avoided)
        const hasCollectionScan =
          explanation.executionStats.executionStages.stage === "COLLSCAN";
        expect(hasCollectionScan).toBe(false);

        console.log(
          `Query ${JSON.stringify(query)} used index: ${
            explanation.executionStats.executionStages.indexName
          }`
        );
      }
    });
  });

  describe("Connection Pool Performance", () => {
    it("handles concurrent connections efficiently", async () => {
      const concurrentOperations = [];
      const operationCount = 50;

      // Create many concurrent database operations
      for (let i = 0; i < operationCount; i++) {
        concurrentOperations.push(
          db.users.findOne({ id: `user${i % 10}` }) // Reuse some queries for caching test
        );
      }

      const startTime = Date.now();

      const results = await Promise.all(concurrentOperations);

      const endTime = Date.now();
      const totalDuration = endTime - startTime;

      // Should handle concurrent operations efficiently
      expect(totalDuration).toBeLessThan(1000); // Under 1 second for 50 operations
      expect(results).toHaveLength(operationCount);

      // Verify connection pool didn't get exhausted
      const poolStats = await performanceMonitor.getConnectionPoolStats();
      expect(poolStats.available).toBeGreaterThan(0);

      console.log(
        `${operationCount} concurrent operations: ${totalDuration}ms`
      );
    });
  });

  async function seedLargeDataset() {
    // Create realistic test data volumes for performance testing
    const users = [];
    const orders = [];

    for (let i = 0; i < 10000; i++) {
      users.push({
        id: `user${i}`,
        email: `user${i}@example.com`,
        firstName: `FirstName${i}`,
        lastName: `LastName${i}`,
        department: ["Engineering", "Sales", "Marketing", "Support"][i % 4],
        role: ["Developer", "Manager", "Analyst", "Lead"][i % 4],
        isActive: i % 10 !== 0, // 90% active users
        createdAt: new Date(
          Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000
        ),
      });

      // Create 0-5 orders per user
      const orderCount = Math.floor(Math.random() * 6);
      for (let j = 0; j < orderCount; j++) {
        orders.push({
          id: `order${i}_${j}`,
          userId: `user${i}`,
          total: Math.floor(Math.random() * 50000) + 1000,
          status: ["pending", "completed", "cancelled"][
            Math.floor(Math.random() * 3)
          ],
          createdAt: new Date(
            Date.now() - Math.random() * 180 * 24 * 60 * 60 * 1000
          ),
        });
      }
    }

    await db.users.insertMany(users);
    await db.orders.insertMany(orders);

    // Create indexes for performance testing
    await db.users.createIndex({ email: 1 });
    await db.users.createIndex({ department: 1, role: 1 });
    await db.users.createIndex({ isActive: 1, createdAt: -1 });
    await db.orders.createIndex({ userId: 1 });
    await db.orders.createIndex({ status: 1, createdAt: -1 });
  }
});

class DatabasePerformanceMonitor {
  constructor(db) {
    this.db = db;
    this.initialStats = null;
  }

  async getQueryCount() {
    const stats = await this.db.admin().serverStatus();
    return stats.opcounters.query + stats.opcounters.command;
  }

  async getConnectionPoolStats() {
    const stats = await this.db.admin().serverStatus();
    return {
      available: stats.connections.available,
      current: stats.connections.current,
      totalCreated: stats.connections.totalCreated,
    };
  }
}

Test-Driven Development: Design Through Testing

Professional TDD Workflow Implementation

TDD cycle that improves code design through testing first:

// ✅ TDD example: Building a subscription billing service
// Following Red-Green-Refactor cycle

describe("SubscriptionBillingService TDD", () => {
  // RED: Write failing test first
  describe("calculateNextBillingAmount - RED Phase", () => {
    it("should calculate prorated amount for mid-cycle upgrade", () => {
      // Test defines the API we want
      const billingService = new SubscriptionBillingService();

      const result = billingService.calculateNextBillingAmount({
        currentPlan: { price: 1000, name: "basic" }, // $10.00
        newPlan: { price: 3000, name: "premium" }, // $30.00
        daysRemaining: 15,
        daysInCycle: 30,
      });

      // Test drives the design - what should the result look like?
      expect(result).toEqual({
        proratedAmount: 1000, // ($30 - $10) * (15/30) = $10.00
        nextCycleAmount: 3000,
        description: "Prorated upgrade from basic to premium",
        effectiveDate: expect.any(Date),
      });

      // This test FAILS because SubscriptionBillingService doesn't exist yet
    });
  });

  // GREEN: Write minimal code to make test pass
  class SubscriptionBillingService {
    calculateNextBillingAmount({
      currentPlan,
      newPlan,
      daysRemaining,
      daysInCycle,
    }) {
      const priceDifference = newPlan.price - currentPlan.price;
      const proratedAmount = Math.round(
        priceDifference * (daysRemaining / daysInCycle)
      );

      return {
        proratedAmount,
        nextCycleAmount: newPlan.price,
        description: `Prorated upgrade from ${currentPlan.name} to ${newPlan.name}`,
        effectiveDate: new Date(),
      };
    }
  }

  // RED: Add more specific test cases
  describe("calculateNextBillingAmount - More RED Phase", () => {
    let billingService;

    beforeEach(() => {
      billingService = new SubscriptionBillingService();
    });

    it("should handle downgrade with refund calculation", () => {
      const result = billingService.calculateNextBillingAmount({
        currentPlan: { price: 3000, name: "premium" },
        newPlan: { price: 1000, name: "basic" },
        daysRemaining: 10,
        daysInCycle: 30,
      });

      expect(result).toEqual({
        proratedAmount: -667, // Negative for refund: ($10 - $30) * (10/30)
        nextCycleAmount: 1000,
        description: "Prorated downgrade from premium to basic with refund",
        effectiveDate: expect.any(Date),
        isRefund: true,
      });

      // This test FAILS - our implementation doesn't handle downgrades
    });

    it("should validate plan data before calculation", () => {
      expect(() => {
        billingService.calculateNextBillingAmount({
          currentPlan: null, // Invalid input
          newPlan: { price: 3000, name: "premium" },
          daysRemaining: 15,
          daysInCycle: 30,
        });
      }).toThrow("Invalid plan data provided");

      // This test FAILS - no validation implemented
    });

    it("should handle same-plan changes (no billing impact)", () => {
      const result = billingService.calculateNextBillingAmount({
        currentPlan: { price: 2000, name: "standard" },
        newPlan: { price: 2000, name: "standard" },
        daysRemaining: 15,
        daysInCycle: 30,
      });

      expect(result).toEqual({
        proratedAmount: 0,
        nextCycleAmount: 2000,
        description: "No billing change - same plan",
        effectiveDate: expect.any(Date),
      });

      // This test FAILS - not handled in current implementation
    });
  });

  // GREEN: Expand implementation to handle new test cases
  class ImprovedSubscriptionBillingService {
    calculateNextBillingAmount({
      currentPlan,
      newPlan,
      daysRemaining,
      daysInCycle,
    }) {
      // Validation (driven by test)
      this.validateInput({ currentPlan, newPlan, daysRemaining, daysInCycle });

      const priceDifference = newPlan.price - currentPlan.price;

      // Handle same plan (driven by test)
      if (priceDifference === 0) {
        return {
          proratedAmount: 0,
          nextCycleAmount: newPlan.price,
          description: "No billing change - same plan",
          effectiveDate: new Date(),
        };
      }

      const proratedAmount = Math.round(
        priceDifference * (daysRemaining / daysInCycle)
      );
      const isRefund = proratedAmount < 0;

      return {
        proratedAmount,
        nextCycleAmount: newPlan.price,
        description: this.buildDescription(currentPlan, newPlan, isRefund),
        effectiveDate: new Date(),
        ...(isRefund && { isRefund: true }),
      };
    }

    validateInput({ currentPlan, newPlan, daysRemaining, daysInCycle }) {
      if (!currentPlan || !newPlan) {
        throw new Error("Invalid plan data provided");
      }

      if (
        typeof currentPlan.price !== "number" ||
        typeof newPlan.price !== "number"
      ) {
        throw new Error("Plan prices must be numbers");
      }

      if (daysRemaining < 0 || daysInCycle <= 0) {
        throw new Error("Invalid billing cycle data");
      }
    }

    buildDescription(currentPlan, newPlan, isRefund) {
      if (isRefund) {
        return `Prorated downgrade from ${currentPlan.name} to ${newPlan.name} with refund`;
      } else {
        return `Prorated upgrade from ${currentPlan.name} to ${newPlan.name}`;
      }
    }
  }

  // REFACTOR: Improve code structure while keeping tests green
  describe("calculateNextBillingAmount - REFACTOR Phase", () => {
    let billingService;

    beforeEach(() => {
      billingService = new RefactoredSubscriptionBillingService();
    });

    it("maintains all existing functionality after refactor", async () => {
      // All previous tests should still pass with refactored implementation

      // Test upgrade scenario
      const upgradeResult = billingService.calculateNextBillingAmount({
        currentPlan: { price: 1000, name: "basic" },
        newPlan: { price: 3000, name: "premium" },
        daysRemaining: 15,
        daysInCycle: 30,
      });

      expect(upgradeResult.proratedAmount).toBe(1000);

      // Test downgrade scenario
      const downgradeResult = billingService.calculateNextBillingAmount({
        currentPlan: { price: 3000, name: "premium" },
        newPlan: { price: 1000, name: "basic" },
        daysRemaining: 10,
        daysInCycle: 30,
      });

      expect(downgradeResult.isRefund).toBe(true);
      expect(downgradeResult.proratedAmount).toBe(-667);
    });
  });

  // Final refactored implementation with better structure
  class RefactoredSubscriptionBillingService {
    constructor(options = {}) {
      this.roundingPrecision = options.roundingPrecision || 0; // Round to dollars
      this.validator = new BillingInputValidator();
      this.calculator = new ProrationCalculator(this.roundingPrecision);
      this.descriptionBuilder = new BillingDescriptionBuilder();
    }

    calculateNextBillingAmount(billingData) {
      // Validate input (single responsibility)
      this.validator.validate(billingData);

      // Calculate proration (single responsibility)
      const proratedAmount = this.calculator.calculateProration(billingData);

      // Build description (single responsibility)
      const description = this.descriptionBuilder.buildDescription(
        billingData.currentPlan,
        billingData.newPlan,
        proratedAmount < 0
      );

      return {
        proratedAmount,
        nextCycleAmount: billingData.newPlan.price,
        description,
        effectiveDate: new Date(),
        ...(proratedAmount < 0 && { isRefund: true }),
      };
    }
  }

  // Supporting classes (also developed through TDD)
  class BillingInputValidator {
    validate({ currentPlan, newPlan, daysRemaining, daysInCycle }) {
      this.validatePlans(currentPlan, newPlan);
      this.validateCycleData(daysRemaining, daysInCycle);
    }

    validatePlans(currentPlan, newPlan) {
      if (!currentPlan || !newPlan) {
        throw new Error("Invalid plan data provided");
      }

      if (
        typeof currentPlan.price !== "number" ||
        typeof newPlan.price !== "number"
      ) {
        throw new Error("Plan prices must be numbers");
      }

      if (currentPlan.price < 0 || newPlan.price < 0) {
        throw new Error("Plan prices cannot be negative");
      }
    }

    validateCycleData(daysRemaining, daysInCycle) {
      if (
        typeof daysRemaining !== "number" ||
        typeof daysInCycle !== "number"
      ) {
        throw new Error("Billing cycle data must be numbers");
      }

      if (daysRemaining < 0 || daysInCycle <= 0) {
        throw new Error("Invalid billing cycle data");
      }

      if (daysRemaining > daysInCycle) {
        throw new Error("Days remaining cannot exceed cycle length");
      }
    }
  }

  class ProrationCalculator {
    constructor(roundingPrecision = 0) {
      this.roundingPrecision = roundingPrecision;
    }

    calculateProration({ currentPlan, newPlan, daysRemaining, daysInCycle }) {
      if (currentPlan.price === newPlan.price) {
        return 0; // No proration needed for same price
      }

      const priceDifference = newPlan.price - currentPlan.price;
      const prorationFactor = daysRemaining / daysInCycle;
      const proratedAmount = priceDifference * prorationFactor;

      return this.roundAmount(proratedAmount);
    }

    roundAmount(amount) {
      const multiplier = Math.pow(10, this.roundingPrecision);
      return Math.round(amount * multiplier) / multiplier;
    }
  }

  class BillingDescriptionBuilder {
    buildDescription(currentPlan, newPlan, isRefund) {
      if (currentPlan.price === newPlan.price) {
        return "No billing change - same plan";
      }

      const action = isRefund ? "downgrade" : "upgrade";
      const suffix = isRefund ? " with refund" : "";

      return `Prorated ${action} from ${currentPlan.name} to ${newPlan.name}${suffix}`;
    }
  }

  // TDD-driven edge cases and business rules
  describe("Advanced TDD Scenarios", () => {
    let billingService;

    beforeEach(() => {
      billingService = new RefactoredSubscriptionBillingService();
    });

    it("handles leap year february correctly", () => {
      const result = billingService.calculateNextBillingAmount({
        currentPlan: { price: 1000, name: "basic" },
        newPlan: { price: 3000, name: "premium" },
        daysRemaining: 14,
        daysInCycle: 29, // Leap year February
      });

      // Expected: ($30 - $10) * (14/29) = $9.66
      expect(result.proratedAmount).toBe(966); // Rounded to cents
    });

    it("handles annual billing cycles appropriately", () => {
      const result = billingService.calculateNextBillingAmount({
        currentPlan: { price: 120000, name: "annual-basic" }, // $1200/year
        newPlan: { price: 360000, name: "annual-premium" }, // $3600/year
        daysRemaining: 182, // ~6 months remaining
        daysInCycle: 365,
      });

      // Expected: ($3600 - $1200) * (182/365) ≈ $1196
      expect(result.proratedAmount).toBe(119670);
    });
  });
});

// TDD produces better API design through test-first thinking
describe("TDD Benefits Demonstration", () => {
  it("forces you to think about API design first", () => {
    // Test-first approach makes you consider:
    // - What parameters does the function need?
    // - What should it return?
    // - How should errors be handled?
    // - What edge cases exist?

    expect(typeof SubscriptionBillingService).toBe("function");
    expect(() => new SubscriptionBillingService()).not.toThrow();
  });

  it("ensures comprehensive error handling from the start", () => {
    const billingService = new RefactoredSubscriptionBillingService();

    // TDD ensures error cases are handled because tests require them
    expect(() => {
      billingService.calculateNextBillingAmount({
        currentPlan: null,
        newPlan: { price: 1000, name: "basic" },
        daysRemaining: 15,
        daysInCycle: 30,
      });
    }).toThrow("Invalid plan data provided");
  });

  it("creates self-documenting code through test descriptions", () => {
    // Test names become living documentation of what the code should do
    // Tests demonstrate how to use the API
    // Tests capture business requirements in executable form

    expect(true).toBe(true); // This test documents TDD benefits
  });
});

Continuous Testing and CI/CD Integration

Automated Quality Gates and Pipeline Integration

CI/CD pipeline with comprehensive testing integration:

// ✅ GitHub Actions workflow for continuous testing
// .github/workflows/test.yml
name: Continuous Testing Pipeline

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

env:
  NODE_VERSION: '18.x'
  MONGODB_VERSION: '6.0'

jobs:
  # Phase 1: Code Quality and Unit Tests
  unit-tests:
    runs-on: ubuntu-latest

    services:
      mongodb:
        image: mongo:6.0
        env:
          MONGO_INITDB_ROOT_USERNAME: test
          MONGO_INITDB_ROOT_PASSWORD: test
        ports:
          - 27017:27017
        options: >-
          --health-cmd "mongosh --eval 'db.runCommand(\"ping\").ok' --quiet"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:7-alpine
        ports:
          - 6379:6379
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run linting
      run: npm run lint

    - name: Run unit tests with coverage
      run: npm run test:unit -- --coverage
      env:
        NODE_ENV: test
        DATABASE_URL: mongodb://test:test@localhost:27017/test
        REDIS_URL: redis://localhost:6379
        JWT_SECRET: test-secret-key

    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage/lcov.info
        flags: unittests

    - name: Check coverage thresholds
      run: |
        if ! npx nyc check-coverage --lines 85 --functions 85 --branches 80; then
          echo "Coverage thresholds not met"
          exit 1
        fi

  # Phase 2: Integration Tests
  integration-tests:
    runs-on: ubuntu-latest
    needs: unit-tests

    services:
      mongodb:
        image: mongo:6.0
        env:
          MONGO_INITDB_ROOT_USERNAME: test
          MONGO_INITDB_ROOT_PASSWORD: test
        ports:
          - 27017:27017

      # Mock external services for integration testing
      stripe-mock:
        image: stripemock/stripe-mock:latest
        ports:
          - 12111:12111

      mailhog:
        image: mailhog/mailhog:latest
        ports:
          - 1025:1025
          - 8025:8025

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Wait for services to be ready
      run: |
        # Wait for MongoDB
        timeout 60 bash -c 'until nc -z localhost 27017; do sleep 1; done'
        # Wait for Stripe Mock
        timeout 60 bash -c 'until nc -z localhost 12111; do sleep 1; done'
        # Wait for MailHog
        timeout 60 bash -c 'until nc -z localhost 1025; do sleep 1; done'

    - name: Run integration tests
      run: npm run test:integration
      env:
        NODE_ENV: test
        DATABASE_URL: mongodb://test:test@localhost:27017/test_integration
        STRIPE_API_URL: http://localhost:12111
        EMAIL_SMTP_HOST: localhost
        EMAIL_SMTP_PORT: 1025

    - name: Upload integration test results
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: integration-test-results
        path: test-results/integration/

  # Phase 3: API Contract Tests
  contract-tests:
    runs-on: ubuntu-latest
    needs: unit-tests

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Start application
      run: |
        npm run build
        npm start &
        sleep 10 # Wait for app to start
      env:
        NODE_ENV: production
        PORT: 3000
        DATABASE_URL: mongodb://localhost:27017/contract_test

    - name: Run API contract tests
      run: npm run test:contract

    - name: Generate API documentation
      run: npm run generate:api-docs

    - name: Upload API docs
      uses: actions/upload-artifact@v3
      with:
        name: api-documentation
        path: docs/api/

  # Phase 4: Performance Tests
  performance-tests:
    runs-on: ubuntu-latest
    needs: integration-tests
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'

    - name: Install k6
      run: |
        sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
        echo "deb https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
        sudo apt-get update
        sudo apt-get install k6

    - name: Start application for performance testing
      run: |
        npm ci
        npm run build
        npm start &
        sleep 15 # Wait for app to fully start
      env:
        NODE_ENV: production

    - name: Run performance tests
      run: k6 run performance/load-tests/api-load-test.js
      env:
        BASE_URL: http://localhost:3000

    - name: Check performance thresholds
      run: |
        # Performance tests will fail the job if thresholds are not met
        echo "Performance tests completed successfully"

    - name: Upload performance results
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: performance-test-results
        path: performance-results/

  # Phase 5: Security Tests
  security-tests:
    runs-on: ubuntu-latest
    needs: unit-tests

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Run dependency security audit
      run: |
        npm audit --audit-level=moderate

    - name: Run Semgrep security scan
      uses: returntocorp/semgrep-action@v1
      with:
        config: >-
          p/javascript
          p/nodejs
          p/security-audit
          p/owasp-top-ten

    - name: Run CodeQL analysis
      uses: github/codeql-action/analyze@v2
      with:
        languages: javascript

  # Phase 6: End-to-End Tests (on staging environment)
  e2e-tests:
    runs-on: ubuntu-latest
    needs: [integration-tests, contract-tests]
    if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Deploy to staging
      run: |
        # Deploy application to staging environment
        echo "Deploying to staging environment"
        # This would typically use your deployment tool

    - name: Wait for staging deployment
      run: |
        # Wait for staging environment to be ready
        timeout 300 bash -c 'until curl -f ${{ vars.STAGING_URL }}/health; do sleep 5; done'

    - name: Install Playwright
      run: |
        npm ci
        npx playwright install --with-deps

    - name: Run E2E tests
      run: npx playwright test
      env:
        BASE_URL: ${{ vars.STAGING_URL }}
        TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
        TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}

    - name: Upload E2E test results
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: e2e-test-results
        path: test-results/e2e/

    - name: Upload screenshots on failure
      uses: actions/upload-artifact@v3
      if: failure()
      with:
        name: e2e-screenshots
        path: test-results/screenshots/

  # Quality Gate: All tests must pass before merge
  quality-gate:
    runs-on: ubuntu-latest
    needs: [unit-tests, integration-tests, contract-tests, security-tests]
    if: always()

    steps:
    - name: Check test results
      run: |
        if [[ "${{ needs.unit-tests.result }}" != "success" ]]; then
          echo "Unit tests failed"
          exit 1
        fi
        if [[ "${{ needs.integration-tests.result }}" != "success" ]]; then
          echo "Integration tests failed"
          exit 1
        fi
        if [[ "${{ needs.contract-tests.result }}" != "success" ]]; then
          echo "Contract tests failed"
          exit 1
        fi
        if [[ "${{ needs.security-tests.result }}" != "success" ]]; then
          echo "Security tests failed"
          exit 1
        fi
        echo "All quality gates passed!"

Test environment management and data strategy:

// ✅ Test environment and data management system
// tests/utils/TestEnvironmentManager.js
class TestEnvironmentManager {
  constructor() {
    this.environments = {
      unit: new UnitTestEnvironment(),
      integration: new IntegrationTestEnvironment(),
      e2e: new E2ETestEnvironment(),
    };

    this.dataManager = new TestDataManager();
    this.cleanupTasks = [];
  }

  async setupEnvironment(type, config = {}) {
    const environment = this.environments[type];
    if (!environment) {
      throw new Error(`Unknown environment type: ${type}`);
    }

    console.log(`Setting up ${type} test environment...`);

    const setup = await environment.setup(config);

    // Register cleanup task
    this.cleanupTasks.push(() => environment.cleanup());

    return setup;
  }

  async teardownAll() {
    console.log("Cleaning up test environments...");

    for (const cleanup of this.cleanupTasks.reverse()) {
      try {
        await cleanup();
      } catch (error) {
        console.warn("Cleanup error:", error.message);
      }
    }

    this.cleanupTasks = [];
  }
}

class UnitTestEnvironment {
  async setup(config = {}) {
    // Setup for isolated unit tests
    const mockDatabase = new MockDatabase();
    const mockServices = new MockExternalServices();

    // Create test-specific configuration
    const testConfig = {
      database: mockDatabase,
      externalServices: mockServices,
      logLevel: "error", // Reduce noise in tests
      enableMetrics: false,
      ...config,
    };

    return {
      config: testConfig,
      mocks: {
        database: mockDatabase,
        services: mockServices,
      },
    };
  }

  async cleanup() {
    // Unit tests typically don't need cleanup
    // Mocks are automatically garbage collected
  }
}

class IntegrationTestEnvironment {
  constructor() {
    this.testDatabase = null;
    this.testRedis = null;
    this.mockServices = null;
  }

  async setup(config = {}) {
    // Setup real database for integration tests
    this.testDatabase = await this.createTestDatabase();
    this.testRedis = await this.createTestRedis();
    this.mockServices = new MockExternalServices();

    // Setup test data
    await this.seedTestData();

    const testConfig = {
      database: this.testDatabase,
      redis: this.testRedis,
      externalServices: this.mockServices,
      environment: "test",
      ...config,
    };

    return {
      config: testConfig,
      database: this.testDatabase,
      redis: this.testRedis,
      mocks: this.mockServices,
    };
  }

  async createTestDatabase() {
    const { MongoMemoryServer } = require("mongodb-memory-server");
    const { MongoClient } = require("mongodb");

    const mongod = await MongoMemoryServer.create({
      binary: { version: "6.0.0" },
    });

    const uri = mongod.getUri();
    const client = new MongoClient(uri);
    await client.connect();

    const db = client.db("integration_test");

    // Store cleanup reference
    this.mongod = mongod;
    this.mongoClient = client;

    return db;
  }

  async createTestRedis() {
    const Redis = require("redis");
    const client = Redis.createClient({
      host: process.env.REDIS_HOST || "localhost",
      port: process.env.REDIS_PORT || 6379,
      db: 15, // Use separate DB for tests
    });

    await client.connect();
    await client.flushDb(); // Clear any existing test data

    this.redisClient = client;
    return client;
  }

  async seedTestData() {
    // Create minimal test data needed for integration tests
    const testUsers = [
      {
        id: "test-user-1",
        email: "test1@example.com",
        firstName: "Test",
        lastName: "User",
        role: "user",
        isActive: true,
        createdAt: new Date(),
      },
      {
        id: "test-admin-1",
        email: "admin@example.com",
        firstName: "Admin",
        lastName: "User",
        role: "admin",
        isActive: true,
        createdAt: new Date(),
      },
    ];

    await this.testDatabase.collection("users").insertMany(testUsers);

    // Create test API keys
    const testApiKeys = [
      {
        id: "test-api-key-1",
        userId: "test-user-1",
        key: "test_key_123",
        permissions: ["read", "write"],
        expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
      },
    ];

    await this.testDatabase.collection("api_keys").insertMany(testApiKeys);
  }

  async cleanup() {
    if (this.redisClient) {
      await this.redisClient.flushDb();
      await this.redisClient.quit();
    }

    if (this.mongoClient) {
      await this.mongoClient.close();
    }

    if (this.mongod) {
      await this.mongod.stop();
    }
  }
}

class E2ETestEnvironment {
  async setup(config = {}) {
    // E2E tests typically run against staging/test environments
    const baseUrl = process.env.E2E_BASE_URL || "http://localhost:3000";

    // Ensure test environment is ready
    await this.waitForEnvironment(baseUrl);

    // Setup test data in target environment
    await this.setupE2ETestData(baseUrl);

    return {
      baseUrl,
      testUsers: this.getE2ETestUsers(),
      config: {
        headless: process.env.CI === "true",
        slowMo: process.env.CI === "true" ? 0 : 100,
        ...config,
      },
    };
  }

  async waitForEnvironment(baseUrl, timeoutMs = 60000) {
    const startTime = Date.now();

    while (Date.now() - startTime < timeoutMs) {
      try {
        const response = await fetch(`${baseUrl}/health`);
        if (response.ok) {
          console.log("E2E environment is ready");
          return;
        }
      } catch (error) {
        // Environment not ready yet
      }

      await new Promise((resolve) => setTimeout(resolve, 1000));
    }

    throw new Error(`E2E environment not ready after ${timeoutMs}ms`);
  }

  async setupE2ETestData(baseUrl) {
    // Create test data via API calls
    const testDataResponse = await fetch(`${baseUrl}/api/test/setup`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.E2E_ADMIN_TOKEN}`,
      },
      body: JSON.stringify({
        createTestUsers: true,
        createTestProducts: true,
        resetTestData: true,
      }),
    });

    if (!testDataResponse.ok) {
      throw new Error("Failed to setup E2E test data");
    }
  }

  getE2ETestUsers() {
    return {
      regular: {
        email: "e2e-user@example.com",
        password: "E2ETestPass123!",
      },
      admin: {
        email: "e2e-admin@example.com",
        password: "E2EAdminPass123!",
      },
      premium: {
        email: "e2e-premium@example.com",
        password: "E2EPremiumPass123!",
      },
    };
  }

  async cleanup() {
    // Clean up E2E test data
    if (process.env.E2E_BASE_URL) {
      try {
        await fetch(`${process.env.E2E_BASE_URL}/api/test/cleanup`, {
          method: "POST",
          headers: {
            Authorization: `Bearer ${process.env.E2E_ADMIN_TOKEN}`,
          },
        });
      } catch (error) {
        console.warn("Failed to cleanup E2E test data:", error.message);
      }
    }
  }
}

// Test data management for consistent test scenarios
class TestDataManager {
  constructor() {
    this.fixtures = new Map();
    this.loadFixtures();
  }

  loadFixtures() {
    // Load test data fixtures
    this.fixtures.set("users", [
      {
        id: "fixture-user-1",
        email: "john.doe@example.com",
        firstName: "John",
        lastName: "Doe",
        role: "user",
        subscription: "basic",
      },
      {
        id: "fixture-admin-1",
        email: "jane.admin@example.com",
        firstName: "Jane",
        lastName: "Admin",
        role: "admin",
        subscription: "premium",
      },
    ]);

    this.fixtures.set("products", [
      {
        id: "fixture-product-1",
        name: "Test Product",
        price: 2999,
        category: "electronics",
        inStock: true,
      },
    ]);

    this.fixtures.set("orders", [
      {
        id: "fixture-order-1",
        userId: "fixture-user-1",
        productId: "fixture-product-1",
        quantity: 2,
        total: 5998,
        status: "completed",
      },
    ]);
  }

  getFixture(name) {
    return this.fixtures.get(name) || [];
  }

  createTestUser(overrides = {}) {
    const baseUser = {
      id: `test-user-${Date.now()}`,
      email: `test-${Date.now()}@example.com`,
      firstName: "Test",
      lastName: "User",
      role: "user",
      isActive: true,
      createdAt: new Date(),
    };

    return { ...baseUser, ...overrides };
  }

  createTestOrder(userId, overrides = {}) {
    const baseOrder = {
      id: `test-order-${Date.now()}`,
      userId,
      total: Math.floor(Math.random() * 10000) + 1000,
      status: "pending",
      createdAt: new Date(),
    };

    return { ...baseOrder, ...overrides };
  }
}

module.exports = { TestEnvironmentManager, TestDataManager };

Key Takeaways

Advanced backend testing completes the quality picture by validating not just correctness, but performance, resilience, and real-world integration scenarios. API testing catches contract changes, performance testing reveals bottlenecks, TDD improves code design, and continuous testing integrates quality gates into deployment pipelines.

The production-ready testing mindset:

  • API testing validates contracts: Comprehensive API tests catch breaking changes, validate error scenarios, and ensure integration compatibility
  • Performance testing reveals bottlenecks: Load testing and performance monitoring identify scalability issues before users encounter them
  • TDD improves design: Test-driven development creates better APIs and more maintainable code through testing-first thinking
  • Continuous testing prevents regressions: Automated quality gates in CI/CD pipelines ensure consistent quality as applications evolve

What distinguishes enterprise testing strategies:

  • API testing that validates contracts, error handling, and real-world integration scenarios comprehensively
  • Performance testing that identifies bottlenecks, validates scalability assumptions, and monitors system behavior under load
  • TDD practices that improve code design, ensure comprehensive error handling, and create self-documenting test suites
  • CI/CD integration with quality gates that prevent regressions and maintain code quality automatically

Series Conclusion

We’ve completed comprehensive backend testing covering unit testing fundamentals, integration validation, API contract testing, performance validation, test-driven development, and continuous testing integration. You now possess the complete testing toolkit for building systems that scale from initial development to enterprise production environments.

The complete backend testing architect’s mastery:

  • Testing pyramid strategy with balanced unit, integration, and end-to-end testing that provides fast feedback and comprehensive coverage
  • Unit and integration testing that validates business logic, component interactions, and database operations with sophisticated mocking
  • API and performance testing that ensures contract compliance, reveals scalability bottlenecks, and validates real-world scenarios
  • TDD and continuous testing that improves code design and integrates quality gates into automated deployment pipelines

What’s Next

With testing and quality assurance foundations complete, we move into the code quality and best practices phase of backend development. You’ll learn to implement clean code principles, establish team coding standards, create comprehensive documentation strategies, and build monitoring systems that maintain quality as applications and teams scale.

Testing ensures your code works correctly. The next phase ensures it remains maintainable, scalable, and operable as your system and organization grow. Quality through testing meets quality through practices to create systems that stand the test of time.

You’re no longer just writing tests—you’re architecting quality systems that catch problems early, prevent regressions, validate performance, and integrate seamlessly into continuous delivery pipelines. The testing foundation is complete. Now we ensure the code itself meets enterprise standards for maintainability and operational excellence.