Testing Framework
Comprehensive testing guide for Mifty applications with built-in testing tools and best practices.
๐งช Testing Philosophyโ
Mifty follows a test-driven development approach with:
- Unit Tests - Test individual components
- Integration Tests - Test module interactions
- End-to-End Tests - Test complete workflows
- API Tests - Test REST endpoints
๐ Quick Startโ
Running Testsโ
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverage
# Run specific test file
npm test user.service.test.ts
Generated Testsโ
Mifty automatically generates comprehensive tests for all your modules:
# Generate modules with tests
npm run generate
# Generated test files:
# src/modules/user/user.service.test.ts
# src/modules/user/user.controller.test.ts
# src/modules/user/user.repository.test.ts
๐ Test Structureโ
Unit Testsโ
// src/modules/user/user.service.test.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
import { UserRepository } from './user.repository';
describe('UserService', () => {
let service: UserService;
let repository: UserRepository;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UserService,
{
provide: UserRepository,
useValue: {
create: jest.fn(),
findById: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
},
},
],
}).compile();
service = module.get<UserService>(UserService);
repository = module.get<UserRepository>(UserRepository);
});
describe('create', () => {
it('should create a user successfully', async () => {
const userData = {
email: 'test@example.com',
firstName: 'John',
lastName: 'Doe',
};
const expectedUser = { id: '1', ...userData };
jest.spyOn(repository, 'create').mockResolvedValue(expectedUser);
const result = await service.create(userData);
expect(repository.create).toHaveBeenCalledWith(userData);
expect(result).toEqual(expectedUser);
});
});
});
Integration Testsโ
// src/modules/user/user.integration.test.ts
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from '../../app.module';
describe('User Integration Tests', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterEach(async () => {
await app.close();
});
describe('/users (POST)', () => {
it('should create a new user', () => {
return request(app.getHttpServer())
.post('/users')
.send({
email: 'test@example.com',
firstName: 'John',
lastName: 'Doe',
})
.expect(201)
.expect((res) => {
expect(res.body.email).toBe('test@example.com');
expect(res.body.id).toBeDefined();
});
});
});
});
๐ง Test Configurationโ
Jest Configurationโ
// jest.config.js
module.exports = {
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: 'src',
testRegex: '.*\\.spec\\.ts$|.*\\.test\\.ts$',
transform: {
'^.+\\.(t|j)s$': 'ts-jest',
},
collectCoverageFrom: [
'**/*.(t|j)s',
'!**/*.spec.ts',
'!**/*.test.ts',
'!**/node_modules/**',
],
coverageDirectory: '../coverage',
testEnvironment: 'node',
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
};
Test Database Setupโ
// src/test/setup.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient({
datasources: {
db: {
url: process.env.DATABASE_URL_TEST,
},
},
});
beforeAll(async () => {
// Setup test database
await prisma.$connect();
});
afterAll(async () => {
// Cleanup test database
await prisma.$disconnect();
});
beforeEach(async () => {
// Clean database before each test
const tablenames = await prisma.$queryRaw<
Array<{ tablename: string }>
>`SELECT tablename FROM pg_tables WHERE schemaname='public'`;
for (const { tablename } of tablenames) {
if (tablename !== '_prisma_migrations') {
await prisma.$executeRawUnsafe(`TRUNCATE TABLE "public"."${tablename}" CASCADE;`);
}
}
});
๐ฏ Testing Best Practicesโ
Test Organizationโ
src/
โโโ modules/
โ โโโ user/
โ โโโ user.service.ts
โ โโโ user.service.test.ts # Unit tests
โ โโโ user.controller.ts
โ โโโ user.controller.test.ts # Unit tests
โ โโโ user.integration.test.ts # Integration tests
โโโ test/
โ โโโ setup.ts # Test setup
โ โโโ helpers/ # Test utilities
โ โโโ fixtures/ # Test data
โโโ e2e/
โโโ user.e2e-spec.ts # End-to-end tests
Test Data Managementโ
// src/test/fixtures/user.fixture.ts
export const userFixture = {
validUser: {
email: 'john@example.com',
firstName: 'John',
lastName: 'Doe',
},
invalidUser: {
email: 'invalid-email',
firstName: '',
lastName: 'Doe',
},
};
// src/test/helpers/database.helper.ts
export class DatabaseHelper {
static async createUser(data = userFixture.validUser) {
return prisma.user.create({ data });
}
static async cleanUsers() {
return prisma.user.deleteMany();
}
}
๐จ Testing Strategiesโ
Test-Driven Development (TDD)โ
- Write Test First - Define expected behavior
- Run Test - Ensure it fails
- Write Code - Implement functionality
- Run Test - Ensure it passes
- Refactor - Improve code quality
Behavior-Driven Development (BDD)โ
describe('User Registration', () => {
describe('Given valid user data', () => {
describe('When creating a user', () => {
it('Then should return created user with ID', async () => {
// Test implementation
});
});
});
describe('Given invalid email', () => {
describe('When creating a user', () => {
it('Then should throw validation error', async () => {
// Test implementation
});
});
});
});
๐ Test Coverageโ
Coverage Reportsโ
# Generate coverage report
npm run test:coverage
# View coverage in browser
open coverage/lcov-report/index.html
Coverage Targetsโ
- Statements: 90%+
- Branches: 85%+
- Functions: 90%+
- Lines: 90%+
๐ Debugging Testsโ
Debug Configurationโ
// .vscode/launch.json
{
"configurations": [
{
"name": "Debug Jest Tests",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["--runInBand", "--no-cache"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
}
]
}
Debug Commandsโ
# Debug specific test
npm run test:debug user.service.test.ts
# Debug with breakpoints
node --inspect-brk node_modules/.bin/jest --runInBand
๐ Advanced Testingโ
Mocking External Servicesโ
// src/test/mocks/email.service.mock.ts
export const mockEmailService = {
sendEmail: jest.fn().mockResolvedValue({ success: true }),
sendBulkEmail: jest.fn().mockResolvedValue({ success: true }),
};
// In your test
beforeEach(() => {
jest.clearAllMocks();
});
Testing Async Operationsโ
describe('Async Operations', () => {
it('should handle async operations', async () => {
const promise = service.asyncOperation();
// Test pending state
expect(service.isLoading).toBe(true);
const result = await promise;
// Test completed state
expect(service.isLoading).toBe(false);
expect(result).toBeDefined();
});
});
๐ Resourcesโ
- Jest Documentation - Official Jest Docs
- Testing Library - Testing Best Practices
- NestJS Testing - NestJS Testing Guide
- Prisma Testing - Database Testing