Skip to content
IRC-CodingIRC-Coding
API TestingUnit TestsIntegration TestsContract TestsTest StrategyConsumer Driven Contracts

API Testing: Unit, Integration, and Contract Tests

Master API testing with unit tests, integration tests, contract tests, strategies, tools, and best practices for reliable APIs.

S

schutzgeist

6 min read
API Testing: Unit, Integration, and Contract Tests

API Testing: Unit, Integration, and Contract Tests

Reliable APIs require a well-thought-out testing strategy that combines unit tests, integration tests, and contract tests to catch issues early and protect interface contracts.

Overview

API testing encompasses all testing activities that ensure an API’s correctness, security, performance, and stability. Unit tests verify isolated functions, controllers, or handlers without external dependencies. Integration tests check how multiple components work together—the API, database, and external services. Contract tests ensure that both the API provider and its consumers adhere to the same contract, whether defined through OpenAPI or Pact. A solid testing strategy covers the API at different levels, runs automatically, and integrates into your CI/CD pipeline. The goal is to catch bugs early, prevent regressions, and reliably document and protect the contract between your API and its clients.

Key Components

Unit Tests for APIs

Unit tests verify small, isolated pieces of your API: handlers, controllers, validation logic, or data mappers. External dependencies like databases or HTTP clients are replaced with mocks or stubs. Unit tests run fast and give quick feedback when you make changes.

Integration Tests

Integration tests verify how your API works with real or containerized dependencies. This includes database access, message queues, external APIs, and authentication services. Testcontainers make it straightforward to spin up databases or other services in your test environment.

End-to-End Tests

End-to-End tests simulate the API from a client’s perspective. They send real HTTP requests and verify the complete response. Tools like Postman, REST Assured, or Supertest are commonly used. E2E tests are slower but cover the entire stack.

Contract Tests

Contract tests verify that both the API and its clients honor the agreed contract. The contract may be defined through OpenAPI, JSON Schema, or frameworks like Pact. Consumer Driven Contracts allow clients to communicate their expectations to the provider.

Consumer Driven Contracts

With Consumer Driven Contracts, clients write their expectations as a formal contract. The provider must satisfy this contract. Pact is a popular framework for this approach. It prevents API changes from silently breaking client code.

The Test Pyramid

The test pyramid dictates that you should have many fast unit tests, fewer integration tests, and only a few slow E2E tests. Contract tests fit into the pyramid between unit and integration levels. They help you verify interface contracts efficiently.

Test Data and Fixtures

Test data should be reproducible and isolated. Fixtures, factories, or setup methods generate the data you need before each test. Database tests should use transactions or fresh databases to keep state isolated between tests.

Mocking and Stubbing

Mocking replaces external dependencies with controlled objects. Stubbing provides predefined responses. Both techniques are essential for unit tests but not for integration tests, where you use real dependencies.

Fuzzing and Negative Tests

Negative tests verify how your API handles invalid input, missing fields, or unexpected data types. Fuzzing automatically generates many random or semi-random inputs to uncover weaknesses.

Performance Tests

Performance tests check response times, throughput, and behavior under load. Tools like k6, JMeter, or Gatling are standard choices. They complement functional tests and matter for APIs with high availability or scalability demands.

CI/CD Integration

API tests should run automatically in your CI/CD pipeline. Unit tests execute on every build, integration tests before merge, contract tests when the API changes, and E2E tests before deployment. Failed tests halt the build early.

Practical Example

A Node.js team tests an order API at all levels.

Unit test for order validation:

describe('Order validation', () => {
  test('rejects negative quantity', () => {
    const result = validateOrder({ customerId: 1, items: [{ productId: 5, quantity: -1 }] });
    expect(result.valid).toBe(false);
    expect(result.errors).toContain('quantity must be positive');
  });
});

Integration test with testcontainers:

describe('POST /orders', () => {
  test('creates an order and persists it', async () => {
    const response = await request(app)
      .post('/orders')
      .send({ customerId: 1, items: [{ productId: 5, quantity: 2 }] })
      .expect(201);

    expect(response.body.id).toBeDefined();
    expect(response.body.status).toBe('created');

    const order = await db.query('SELECT * FROM orders WHERE id = ?', [response.body.id]);
    expect(order).toHaveLength(1);
  });
});

Contract test with Pact:

const pact = new Pact({
  consumer: 'web-shop',
  provider: 'order-service',
});

await pact.addInteraction({
  state: 'order can be created',
  uponReceiving: 'a request to create an order',
  withRequest: {
    method: 'POST',
    path: '/orders',
    body: { customerId: 1, items: [{ productId: 5, quantity: 2 }] }
  },
  willRespondWith: {
    status: 201,
    body: { id: 1, status: 'created' }
  }
});

By combining all three levels, the API is tested thoroughly and early in the development cycle.

FAQ: API Testing

1. What is API Testing?

API testing encompasses all testing activities that ensure an API’s correctness, security, performance, and stability. It includes unit, integration, contract, and end-to-end tests.

2. What is a unit test for APIs?

A unit test for APIs verifies isolated functions such as handlers, controllers, or validation logic. External dependencies are replaced with mocks.

3. What is an integration test?

An integration test verifies how multiple components work together: the API, database, external services, or message queues. Real or containerized dependencies are used.

4. What is a contract test?

A contract test ensures that the API provider and its consumers adhere to the same contract. The contract may be defined through OpenAPI, JSON Schema, or Pact.

5. What is Consumer Driven Contract Testing?

Consumer Driven Contract Testing means clients define their expectations of the API as a formal contract. The provider must honor these contracts to prevent silent breaking changes.

6. What is Pact?

Pact is a framework for Consumer Driven Contract Testing. It generates contracts from consumer tests and later verifies them against the provider.

7. What is the test pyramid?

The test pyramid states you should have many fast unit tests, fewer integration tests, and only a few slow E2E tests. Contract tests fit between unit and integration levels.

8. What is mocking?

Mocking replaces external dependencies with controlled objects that return predefined responses. It’s mainly used in unit tests.

9. What are testcontainers?

Testcontainers are containerized dependencies—databases, message queues, caches—that spin up during tests. They enable realistic integration tests without manual infrastructure setup.

10. What is an end-to-end test?

An end-to-end test sends real HTTP requests to your API and verifies the complete response. It covers the entire stack but runs slower and requires more maintenance than unit tests.

11. What are negative tests?

Negative tests verify how your API behaves with invalid or incomplete input. They ensure errors are handled correctly.

12. What is fuzzing?

Fuzzing automatically generates many random or semi-random inputs to uncover weaknesses, crashes, or unexpected behavior in your API.

13. What are performance tests for APIs?

Performance tests measure response times, throughput, and behavior under load. Tools like k6, JMeter, or Gatling help identify bottlenecks.

14. Why should API tests run in CI/CD?

Automated tests in CI/CD catch issues before they reach production. They safeguard refactorings, prevent regressions, and maintain consistent quality.

15. What are best practices for API testing?

Best practices include a balanced test pyramid, isolated and reproducible test data, clear responsibilities for each test level, contract tests for interfaces, automated CI/CD execution, and regular performance testing.

Next in the API Learning Path

The next article in the API Learning Path covers API Rate Limiting Implementation — how to implement rate limiting in APIs using Token Bucket, Sliding Window, and Redis.

References

  1. https://martinfowler.com/articles/consumerDrivenContracts.html
  2. https://docs.pact.io/
  3. https://www.testcontainers.org/

If you’d like to explore API testing, test automation, and software quality further, we recommend the following books:

API Development

Books about API design, REST, GraphQL, OpenAPI and API architecture

Designing Data-Intensive Applications von Martin Kleppmann

Designing Data-Intensive Applications von Martin Kleppmann

Bei Amazon ansehen

Affiliate-Link: Bei einem Kauf erhalten wir möglicherweise eine Provision.

API Design Patterns von JJ Geewax

API Design Patterns von JJ Geewax

Bei Amazon ansehen

Affiliate-Link: Bei einem Kauf erhalten wir möglicherweise eine Provision.

Back to Blog
Share:

Related Posts