Skip to content

Latest commit

 

History

History
127 lines (93 loc) · 3.44 KB

File metadata and controls

127 lines (93 loc) · 3.44 KB

Integration Testing

What is Integration Testing?

Integration testing checks how different parts of your app work together.

Instead of testing a single function or isolated component, you test multiple units interacting — for example, a component + its child components + API calls + state updates.

Example scenarios:

  • A form component interacting with a validation hook and a submit handler.
  • A parent component passing props to multiple children and updating state based on events.
  • A data-fetching component rendering a loader, showing fetched data, and handling errors.

Why Integration Testing?

  • Catches issues between modules/components (gaps unit tests miss).
  • Verifies that data flows correctly between parts.
  • Ensures UI and business logic work together as expected.

Integration Testing vs. Unit Testing vs. E2E

Type Scope Goal Speed
Unit Testing Smallest unit (function/component) Test internal logic in isolation Fast
Integration Testing Multiple units/modules working together Test their interaction Medium
End-to-End (E2E) Whole app in a real browser Test full user flows Slow

Example – React Integration Test

Here we test:

  • Parent component → fetches data
  • Child component → displays items
  • API interaction → mocked
// UserList.js
import { useEffect, useState } from 'react';

function User({ name }) {
  return <li>{name}</li>;
}

export default function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/users')
      .then((res) => res.json())
      .then((data) => {
        setUsers(data);
        setLoading(false);
      });
  }, []);

  if (loading) return <p>Loading...</p>;

  return (
    <ul>
      {users.map((user) => (
        <User key={user} name={user} />
      ))}
    </ul>
  );
}

Test:

// UserList.test.js
import { render, screen, waitFor } from '@testing-library/react';
import UserList from './UserList';

beforeEach(() => {
  global.fetch = jest.fn(() =>
    Promise.resolve({
      json: () => Promise.resolve(['Alice', 'Bob']),
    })
  );
});

test('loads and displays users', async () => {
  render(<UserList />);

  // Initial state
  expect(screen.getByText(/loading/i)).toBeInTheDocument();

  // Wait for users to load
  await waitFor(() => {
    expect(screen.getByText('Alice')).toBeInTheDocument();
    expect(screen.getByText('Bob')).toBeInTheDocument();
  });
});

Tips for Integration Testing

  • Mock APIs → Use Jest mocks or MSW to isolate tests from real network calls.
  • Focus on interactions & data flow → Not on implementation details.
  • Avoid overly large scope → Don’t turn integration tests into full E2E tests.
  • Use waitFor or findBy → For async state changes.
  • Test critical paths → Data fetching, form submission, authentication.

Where Integration Tests Fit in the Testing Pyramid

 ▲
 | End-to-End Tests (few)
 | Integration Tests (moderate)
 | Unit Tests (many)
 ▼
  • Unit tests → Verify building blocks
  • Integration tests → Verify blocks fit together
  • E2E → Verify entire house works for the user