Integration and Contract Tests

By Syncfusion®, Inc. · Last updated

See an over-mocked unit test pass while the real API changes. Catch it with an integration test and a contract test, make contracts strict, keep mocks honest, and learn what to mock and what to run for real.

When Parts Meet

Most apps have parts that talk to each other:

  • the frontend (the page) asks the backend (the server) for data
  • your code calls a payment service
  • one team's API is used by another team's code

Each part can pass its own tests and still break when they meet.

In this lesson, you will see a unit test stay green while the real API changes. Then you will add the two kinds of test that catch it: an integration test and a contract test.

Simple lesson: parts that work alone can still fail together.

A Real-World Example

Think about a plug and a socket.

  • The plug factory tests its plugs. Every plug is perfect.
  • The socket factory tests its sockets. Every socket is perfect.
  • But one factory changed from round pins to flat pins.
  • At home, the plug does not fit the socket.

What would have caught it?

  1. Trying the real plug in the real socket. That is an integration test.
  2. A written shape that both factories check against. That is a contract.

What You Will Learn

In this lesson, you will learn:

  1. How a mock can hide a real API change.
  2. What an integration test is, and when to write one.
  3. What a contract and a contract test are.
  4. How to make a contract strict enough to catch changes.
  5. How to keep your mocks honest with the same contract.
  6. When to mock and when to use the real code.

The Mock That Hid the Change

The Setup

The order page shows the order total, like "₹330.00".

  • src/server.ts is the backend. It answers GET /orders/7.
  • src/client.ts is the frontend code. It reads order.total.
  • src/http.ts is the lab's network. It passes the request to the server.

The backend team just changed the API. total is now totalPaise. Nobody told the frontend.

Press ▶ Run tests. Green.

  • The test: a mock (vi.fn().mockResolvedValue(...)) returns { id: 7, total: 330 }.
  • The real server: now returns totalPaise: 33000. Open src/server.ts to see it.
  • Why it is green: the test never talks to the real server. The mock still has the old shape.

In the real world, the network call goes over HTTP to a running server. In this lab, src/http.ts passes the request straight to the server function, in your browser. The tests you write are the same.

Simple lesson: a mock shows the API as it was when someone wrote the mock, not as it is today.

Integration Tests

Integration test = a test where two or more real parts run together.

Press ▶ Run tests.

  • The Tests tab: red. "Cannot read properties of undefined (reading 'toFixed')".
  • Why: with the real server, order.total does not exist any more.
  • Now try: open src/server.ts and change totalPaise: 33000 back to total: 330. Run again. Green.

Integration tests are slower and need more set-up than unit tests. Use them where parts meet: your API, your database, a service you call.

Simple lesson: unit tests check each part. Integration tests check that the parts fit.

Contract Tests

What a Contract Is

Contract = a written agreement about the shape of the data two parts send each other.

For the order API, the contract says:

  • id is a whole number
  • total is a number, 0 or more
  • currency is the text "INR"
  • all three must be there

It is often written as a JSON Schema. That is a standard way to describe the shape of JSON data.

Contract test = a test that checks real data against the contract.

Press ▶ Run tests.

  • The Tests tab: red. The list says $.total is missing.
  • Why it helps: the backend team would see this the moment they renamed the field, before the frontend broke.
  • Open src/order-contract.ts to read the contract.

Animation: the server sends a response with totalPaise. It is held against the contract shape which needs total. The missing piece turns red and the contract test fails before the page breaks.

Server totalPaise: 33000

Contract

✓ id ? total ✓ currency

Order page safe: change caught

$.total is missing → contract test fails

The contract stops the changed response before it reaches the page.

A Contract That Is Too Loose

A contract only helps if it says enough.

Press ▶ Run tests. Green, even though total is missing.

  • Why: this contract has no required list. Missing fields are allowed.
  • Now try: add required: ['id', 'total', 'currency'], and a currency property. Run again. Red.

A useful contract says:

  • which fields are required
  • the type of each field (integer, number, string)
  • allowed values, with enum or minimum, where they matter

Keep the Mock Honest

Mocks are still useful. They make unit tests fast. The trick is to check the mock's fake data against the same contract.

Press ▶ Run tests. Green.

  • Test 1: checks the fake order matches the contract.
  • Test 2: uses the fake order in a fast unit test.
  • If the contract changes, test 1 fails, and you know to update the mock.

Simple lesson: one contract, checked on both sides, keeps the server, the client and the mocks in step.

When to Mock

Mock only what is outside your code, slow, costly or changing on its own.

Mock these: the network to other companies, the clock, random numbers, emails and payments.

Do not mock these: your own small functions, plain maths, and above all the code the test is about.

Agents often mock more than they need to. When you review an AI test with vi.fn(), ask: does the real code still run?

Simple lesson: mock the edges, not the middle.

TL;DR

  1. Integration test = real parts running together, like the client and the server.
  2. Contract = the agreed shape of the data between two parts.
  3. JSON Schema = a standard way to write that shape.
  4. Contract test = checks real data against the contract.
  5. A good contract lists the required fields, the types and the allowed values.
  6. Honest mock = fake data that also passes the contract.
  7. Mock the edges (network, clock, email, payments), not the middle (your own code).

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
Only mocked tests"The unit test passes, so the page works."Add one integration test where parts meet.An API change breaks the page in production.
A loose contract"Listing the fields is enough."Mark them required and give types.A missing field still passes.
Mocks that drift"I wrote the mock once. It is fine."Check mock data against the contract.Mocks keep the old shape for months.
Mocking your own maths"Mock everything except one line."Let your own code run.Real bugs hide behind the mock.
Contract on one side only"The server team checks it."Check it on both sides.The client and the mock drift apart.

Check Your Understanding

Exercises

What to Remember

  • A mock shows the API as it was, not as it is.
  • Write an integration test where your parts meet.
  • A contract is the agreed shape of the data. Check it with a contract test.
  • Make contracts strict: required fields, types, allowed values.
  • Check your mocks against the same contract.
  • Mock the edges, not your own code.

Further Reading

Next: User-Flow Checks. Every unit test passes, but checkout is broken. You will catch it with a flow test, then export your first verification pack.