# Testing (/docs/composer/testing) > For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL. Test composed services by deciding what service.load() returns, with mockService for unit tests and bootstrapService for integration tests. Location: Composer > Testing Your app's code gets every dependency from one call, `service.load()`, and nothing from arguments or globals. That makes testing a matter of deciding what `load()` returns; the code under test is never modified. There are two tools, and you pick by how much of the real path you want to exercise: | You want to... | Use | From | | ------------------------------------------------------------ | ------------------ | --------------------------------------- | | Call a page, action, or handler directly, dependencies faked | `mockService` | `@prisma/composer/testing` | | Boot the real built entry and drive it over real HTTP | `bootstrapService` | `@prisma/composer-prisma-cloud/testing` | Most tests are the first kind. Reach for the second when the thing you are proving is the wiring itself: that the service boots, reads its config, builds its clients, and answers requests. ## Unit tests: `mockService` [#unit-tests-mockservice] `mockService(service, overrides)` returns a copy of the service whose `load()` yields your fakes and whose `input()` yields the object you pass under the reserved `input` key. Everything goes in one flat object: dependency names route to `load()`, and `input` routes to `input()` (required exactly when the service declares an input schema; the input double is handed over as-is, not validated). The fakes are type-checked against the service's declared dependencies, so a double with the wrong shape does not compile. Substituting the mocked service for the real one is your test runner's job: `vi.mock` in Vitest, `mock.module` in `bun test`. A Vitest example, testing a Next.js page: ```tsx title="app/page.test.tsx" import { renderToString } from 'react-dom/server'; import { mockService } from '@prisma/composer/testing'; import realService from '../src/service.ts'; vi.mock('../src/service.ts', () => ({ default: mockService(realService, { auth: { verify: async () => ({ ok: true }) }, // wrong shape = compile error }), })); import Page from './page.tsx'; it('renders the verified state', async () => { expect(renderToString(await Page())).toContain('Signed in: true'); }); ``` No server, no database, no environment; the page renders against the fake. ## Integration tests: `bootstrapService` [#integration-tests-bootstrapservice] `bootstrapService` boots the service's real built entry in-process, fed the same way a deployed boot is fed, except you choose the values. Point a dependency at a stand-in you run on a loopback port, then make real HTTP requests. Run these under `bun test`: ```ts title="service.integration.test.ts" import { bootstrapService } from '@prisma/composer-prisma-cloud/testing'; import fakeAuth from '@my-app/auth/fake'; // an in-memory handler, no db import storefront from '../src/service.ts'; const fake = Bun.serve({ port: 0, fetch: fakeAuth }); const app = await bootstrapService(storefront, { service: { port: 4310 }, inputs: { auth: { url: fake.url.href } }, }); const res = await app.fetch(new Request(app.url)); expect(await res.text()).toContain('Signed in: true'); ``` Five things to know: * **Build first.** It boots the *built* entry, so the test task must depend on the build. * **Pass a concrete `service.port`.** The entry listens itself; no OS-assigned port is reported back. * **There is no `close()`.** Run each integration-test file in its own process (`bun test` does this per file) and the server dies with it. * **The service's code is untouched.** If you find yourself editing `server.ts` to make it testable, something upstream is wrong. * **You do not need a service key.** Only a deploy (or `dev`) provisions keys; in a test nothing checks, every call reaches your handler, and there is nothing to put in `inputs`. A service with an input schema takes `input` in the config, a binding exactly like `provision()`'s, run through the real serialize and read path, so `input()` in the booted entry sees what a deploy would produce. **Next.js services need a third argument**, a boot function, because the built entry lives inside Next's standalone output. Resolve it with `standaloneServerPath`; `bootstrapService` exports the resolved port as `process.env.PORT` before booting, which is exactly what Next's standalone server binds: ```ts import { pathToFileURL } from 'node:url'; import { standaloneServerPath } from '@prisma/composer/nextjs/control'; await bootstrapService(storefront, config, async () => { await import(pathToFileURL(standaloneServerPath(storefront.build)).href); }); ``` The complete working version is [`examples/storefront-auth`](https://github.com/prisma/composer/tree/main/examples/storefront-auth) in the Composer repository. ## Writing good fakes [#writing-good-fakes] A dependency's type *is* its contract, so anything of that shape is a valid fake, and the compiler holds it to that. In increasing order of realism: * **A bare object**: `{ verify: async () => ({ ok: true }) }`. Right for most unit tests. * **The real client over an in-memory handler**: exercises JSON encoding and schema validation, still no socket. * **A real local server**: the fake served over actual HTTP, which is what `bootstrapService` drives. One habit pays for all of this. Ship each service's fake from its own package as a `/fake` entry point, outside `src/`, so it cannot reach production code. Fake and service then share one contract; when the contract changes, both stop compiling at once, and every consumer's tests find out immediately. ## Next steps [#next-steps] * [Services and contracts](https://www.prisma.io/docs/composer/services-and-contracts): what the contract types on each end. * [Local development](https://www.prisma.io/docs/composer/local-development): run the real app instead of booting one service. ## Related pages - [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together. - [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself. - [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model. - [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations. - [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.