5.0 KiB
5.0 KiB
trigger
| trigger |
|---|
| always_on |
Testing Patterns for GoodGo Microservices
When to Use This Skill
Use this skill when:
- Writing unit tests for services, controllers, or repositories
- Creating integration tests for middleware chains
- Building E2E tests for API endpoints
- Setting up Jest configuration for a new service
- Mocking external dependencies (Prisma, Redis, Auth SDK)
- Debugging test failures
- Improving test coverage
Core Concepts
Test Types
| Type | Location | Speed | Dependencies |
|---|---|---|---|
| Unit | *.test.ts (next to source) |
<1s | All mocked |
| Integration | __tests__/ |
1-5s | Partial mocking |
| E2E | __tests__/*.e2e.ts |
5-10s | Test DB, mocked external |
Key Patterns
Jest Configuration
// jest.config.ts
export default {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.test.ts', '**/__tests__/**/*.e2e.ts'],
coverageThreshold: { global: { branches: 70, functions: 70, lines: 70 } },
setupFilesAfterEnv: ['<rootDir>/src/__tests__/setupTests.ts'],
};
Unit Test Pattern
describe('FeatureService', () => {
let service: FeatureService;
let mockRepository: any;
beforeEach(() => {
mockRepository = { findById: jest.fn(), create: jest.fn() };
service = new FeatureService(mockRepository);
});
it('should return feature when found', async () => {
mockRepository.findById.mockResolvedValue({ id: '1', name: 'Test' });
const result = await service.findById('1');
expect(result).toEqual({ id: '1', name: 'Test' });
});
});
E2E Test Pattern
describe('POST /api/features', () => {
it('should create a new feature', async () => {
const response = await request
.post('/api/features')
.set('Authorization', 'Bearer valid-token')
.send({ name: 'New Feature' })
.expect(201);
expect(response.body).toMatchObject({ success: true, data: { name: 'New Feature' } });
});
});
Mock Prisma
import { mockDeep } from 'jest-mock-extended';
import { PrismaClient } from '@prisma/client';
export const prismaMock = mockDeep<PrismaClient>();
jest.mock('../prisma', () => ({ default: prismaMock }));
// Usage
prismaMock.user.create.mockResolvedValue({ id: '1', email: 'test@example.com' });
Test Factory
export class TestFactory {
static createUser(overrides = {}) {
return { id: 'test-user-1', email: 'test@example.com', ...overrides };
}
static createAuthToken(userId: string) {
return jwt.sign({ userId }, 'test-secret');
}
}
Best Practices
- Each test is independent and isolated
- Tests follow AAA pattern (Arrange-Act-Assert)
- Mock external dependencies
- Test edge cases and error scenarios
- Keep tests simple and focused
- Use descriptive test names
- Maintain >70% code coverage
Common Mistakes
-
Testing Implementation Details: Tests break on refactoring
// BAD: expect(service['privateMethod']()).toBe(true); // GOOD: expect(await service.processOrder(order)).toEqual({ success: true }); -
Shared Mutable State: Tests affect each other
// BAD: let counter = 0; (shared across tests) // GOOD: beforeEach(() => { counter = 0; }); -
Not Mocking External Services: Tests are slow and flaky
// BAD: await fetch('https://api.example.com/data'); // GOOD: jest.spyOn(httpClient, 'get').mockResolvedValue({ data: mockData }); -
Missing Edge Cases: Only testing happy path
// GOOD: Include error cases test('creates user', async () => { ... }); test('throws on duplicate email', async () => { ... }); test('validates email format', async () => { ... });
Quick Reference
Coverage Targets:
- Global: 70%+ (branches, functions, lines)
- Critical paths: 90%+
- Repositories/Services: 80%+
Essential Commands:
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm test:coverage # With coverage
pnpm test -- --runInBand # Sequential (for debugging)
pnpm test -- UserService # Run specific test file
Mock Imports:
import { mockDeep } from 'jest-mock-extended';
import { prismaMock } from '../__mocks__/prisma';
import supertest from 'supertest';
Debug Tips:
- Use
test.only()to run single test - Use
--detectOpenHandlesfor async issues - Use
--runInBandfor sequential execution - Add
console.log()statements temporarily
Resources
- Jest Documentation - Testing framework
- Supertest - HTTP assertions
- jest-mock-extended - TypeScript mocks
- Detailed Code Examples
- Database Prisma - Database mocking patterns
- Error Handling - Error testing