PrismaMiddleTechnical
Как тестировать код, использующий Prisma? Какие стратегии мокирования доступны?
Для unit-тестов используйте jest-mock-extended для мокирования Prisma Client; для интеграционных тестов — отдельную тестовую БД с prisma migrate deploy в beforeAll.
Стратегии тестирования кода с Prisma
Для тестирования кода, использующего Prisma, применяют три основных подхода: мокирование Prisma Client, использование тестовой базы данных с миграциями и использование in-memory/SQLite.
1. Мокирование с jest-mock-extended
Наиболее популярный подход для unit-тестов — создать мок всего Prisma Client:
// src/__mocks__/prisma.ts
import { PrismaClient } from '@prisma/client';
import { mockDeep, mockReset, DeepMockProxy } from 'jest-mock-extended';
export const prismaMock = mockDeep<PrismaClient>();
beforeEach(() => {
mockReset(prismaMock);
});
// jest.setup.ts
jest.mock('../prisma', () => ({
__esModule: true,
prisma: prismaMock,
}));
В тесте используем типизированный мок:
// user.service.test.ts
import { prismaMock } from '../__mocks__/prisma';
import { createUser } from './user.service';
test('createUser сохраняет пользователя', async () => {
const user = { id: 1, email: 'test@example.com', name: 'Alice' };
prismaMock.user.create.mockResolvedValue(user);
const result = await createUser({ email: 'test@example.com', name: 'Alice' });
expect(result).toEqual(user);
expect(prismaMock.user.create).toHaveBeenCalledWith({
data: { email: 'test@example.com', name: 'Alice' },
});
});
2. Тестовая база данных (интеграционные тесты)
Для интеграционных тестов используют отдельную БД (PostgreSQL или SQLite) и прогоняют миграции перед тестами:
// jest.integration.setup.ts
import { execSync } from 'child_process';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
beforeAll(async () => {
// DATABASE_URL должен указывать на тестовую БД
execSync('npx prisma migrate deploy', {
env: { ...process.env, DATABASE_URL: process.env.TEST_DATABASE_URL },
});
});
afterEach(async () => {
// Очищаем таблицы между тестами
await prisma.user.deleteMany();
await prisma.post.deleteMany();
});
afterAll(async () => {
await prisma.$disconnect();
});
3. SQLite для быстрых интеграционных тестов
Если схема совместима, можно использовать SQLite вместо PostgreSQL — это быстрее в CI:
# .env.test
DATABASE_URL="file:./test.db"
DATABASE_URL="file:./test.db" npx prisma migrate deploy
DATABASE_URL="file:./test.db" npx jest
4. Singleton-паттерн для Prisma Client
Чтобы избежать множества открытых соединений в тестах, используют singleton:
// src/prisma.ts
import { PrismaClient } from '@prisma/client';
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma ||
new PrismaClient({ log: ['error'] });
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma;
}
Подводные камни
- Не забывайте вызывать
mockResetвbeforeEach— иначе моки из предыдущего теста просочатся в следующий. - Мок Prisma Client не проверяет реальные SQL-ограничения (UNIQUE, FK) — интеграционные тесты обязательны для критических путей.
- При использовании SQLite учитывайте несовместимость с PostgreSQL-специфичными типами (
jsonb,uuid,enum). - Миграции в CI должны применяться к чистой тестовой БД, иначе флакообразные ошибки «relation already exists».
- После изменения схемы обязательно перегенерировать Prisma Client (
npx prisma generate), иначе типы в моках устареют. - Не вызывайте
prisma.$disconnect()между тестами — только вafterAll, иначе connection pool исчерпается. - Очистка данных через
deleteManyмедленнееTRUNCATE ... CASCADE; в больших схемах используйте raw-запрос. - В
jest-mock-extendedмок транзакций (prisma.$transaction) требует отдельной настройки — не будет работать по умолчанию.
Common mistakes
- Путает Prisma Client API с гарантиями базы данных: индексы, блокировки и isolation level не создаются магически.
- Не объясняет, где в lifecycle находится тестирование кода с Prisma.
- Не разделяет validation, authorization, business logic и persistence.
- Игнорирует ошибки, лимиты входных данных, observability и тестирование.
What the interviewer is testing
- Может объяснить тестирование кода с Prisma на примере кода.
- Называет ключевые API: test database, mock PrismaClient.
- Отделяет ORM/query builder поведение от реального поведения СУБД.
- Видит production-риски: безопасность, отказоустойчивость, логирование и тесты.