Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/test-use-testing-module.md
1---2title: Use Testing Module for Unit Tests3impact: HIGH4impactDescription: Enables proper isolated testing with mocked dependencies5tags: testing, unit-tests, mocking, jest6---78## Use Testing Module for Unit Tests910Use `@nestjs/testing` module to create isolated test environments with mocked dependencies. This ensures your tests run fast, don't depend on external services, and properly test your business logic in isolation.1112**Incorrect (manual instantiation bypassing DI):**1314```typescript15// Instantiate services manually without DI16describe('UsersService', () => {17it('should create user', async () => {18// Manual instantiation bypasses DI19const repo = new UserRepository(); // Real repo!20const service = new UsersService(repo);2122const user = await service.create({ name: 'Test' });23// This hits the real database!24});25});2627// Test implementation details28describe('UsersController', () => {29it('should call service', async () => {30const service = { create: jest.fn() };31const controller = new UsersController(service as any);3233await controller.create({ name: 'Test' });3435expect(service.create).toHaveBeenCalled(); // Tests implementation, not behavior36});37});38```3940**Correct (use Test.createTestingModule with mocked dependencies):**4142```typescript43// Use Test.createTestingModule for proper DI44import { Test, TestingModule } from '@nestjs/testing';4546describe('UsersService', () => {47let service: UsersService;48let repo: jest.Mocked<UserRepository>;4950beforeEach(async () => {51const module: TestingModule = await Test.createTestingModule({52providers: [53UsersService,54{55provide: UserRepository,56useValue: {57save: jest.fn(),58findOne: jest.fn(),59find: jest.fn(),60},61},62],63}).compile();6465service = module.get<UsersService>(UsersService);66repo = module.get(UserRepository);67});6869afterEach(() => {70jest.clearAllMocks();71});7273describe('create', () => {74it('should save and return user', async () => {75const dto = { name: 'John', email: '[email protected]' };76const expectedUser = { id: '1', ...dto };7778repo.save.mockResolvedValue(expectedUser);7980const result = await service.create(dto);8182expect(result).toEqual(expectedUser);83expect(repo.save).toHaveBeenCalledWith(dto);84});8586it('should throw on duplicate email', async () => {87repo.findOne.mockResolvedValue({ id: '1', email: '[email protected]' });8889await expect(90service.create({ name: 'Test', email: '[email protected]' }),91).rejects.toThrow(ConflictException);92});93});9495describe('findById', () => {96it('should return user when found', async () => {97const user = { id: '1', name: 'John' };98repo.findOne.mockResolvedValue(user);99100const result = await service.findById('1');101102expect(result).toEqual(user);103});104105it('should throw NotFoundException when not found', async () => {106repo.findOne.mockResolvedValue(null);107108await expect(service.findById('999')).rejects.toThrow(NotFoundException);109});110});111});112113// Testing guards and interceptors114describe('RolesGuard', () => {115let guard: RolesGuard;116let reflector: Reflector;117118beforeEach(async () => {119const module = await Test.createTestingModule({120providers: [RolesGuard, Reflector],121}).compile();122123guard = module.get<RolesGuard>(RolesGuard);124reflector = module.get<Reflector>(Reflector);125});126127it('should allow when no roles required', () => {128const context = createMockExecutionContext({ user: { roles: [] } });129jest.spyOn(reflector, 'getAllAndOverride').mockReturnValue(undefined);130131expect(guard.canActivate(context)).toBe(true);132});133134it('should allow admin for admin-only route', () => {135const context = createMockExecutionContext({ user: { roles: ['admin'] } });136jest.spyOn(reflector, 'getAllAndOverride').mockReturnValue(['admin']);137138expect(guard.canActivate(context)).toBe(true);139});140});141142function createMockExecutionContext(request: Partial<Request>): ExecutionContext {143return {144switchToHttp: () => ({145getRequest: () => request,146}),147getHandler: () => jest.fn(),148getClass: () => jest.fn(),149} as ExecutionContext;150}151```152153Reference: [NestJS Testing](https://docs.nestjs.com/fundamentals/testing)154