Files
agent-skills/skills/nestjs-best-practices/rules/test-use-testing-module.md
Jason Woltje 861b28b965 feat: Expand fleet to 23 skills across all domains
New skills (14):
- nestjs-best-practices: 40 priority-ranked rules (kadajett)
- fastapi: Pydantic v2, async SQLAlchemy, JWT auth (jezweb)
- architecture-patterns: Clean Architecture, Hexagonal, DDD (wshobson)
- python-performance-optimization: Profiling and optimization (wshobson)
- ai-sdk: Vercel AI SDK streaming and agent patterns (vercel)
- create-agent: Modular agent architecture with OpenRouter (openrouterteam)
- proactive-agent: WAL Protocol, compaction recovery, self-improvement (halthelobster)
- brand-guidelines: Brand identity enforcement (anthropics)
- ui-animation: Motion design with accessibility (mblode)
- marketing-ideas: 139 ideas across 14 categories (coreyhaines31)
- pricing-strategy: SaaS pricing and tier design (coreyhaines31)
- programmatic-seo: SEO at scale with playbooks (coreyhaines31)
- competitor-alternatives: Comparison page architecture (coreyhaines31)
- referral-program: Referral and affiliate programs (coreyhaines31)

README reorganized by domain: Code Quality, Frontend, Backend,
Auth, AI/Agent Building, Marketing, Design, Meta.

Mosaic Stack is not limited to coding — the Orchestrator serves
coding, business, design, marketing, writing, logistics, and analysis.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:22:53 -06:00

154 lines
4.3 KiB
Markdown

---
title: Use Testing Module for Unit Tests
impact: HIGH
impactDescription: Enables proper isolated testing with mocked dependencies
tags: testing, unit-tests, mocking, jest
---
## Use Testing Module for Unit Tests
Use `@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.
**Incorrect (manual instantiation bypassing DI):**
```typescript
// Instantiate services manually without DI
describe('UsersService', () => {
it('should create user', async () => {
// Manual instantiation bypasses DI
const repo = new UserRepository(); // Real repo!
const service = new UsersService(repo);
const user = await service.create({ name: 'Test' });
// This hits the real database!
});
});
// Test implementation details
describe('UsersController', () => {
it('should call service', async () => {
const service = { create: jest.fn() };
const controller = new UsersController(service as any);
await controller.create({ name: 'Test' });
expect(service.create).toHaveBeenCalled(); // Tests implementation, not behavior
});
});
```
**Correct (use Test.createTestingModule with mocked dependencies):**
```typescript
// Use Test.createTestingModule for proper DI
import { Test, TestingModule } from '@nestjs/testing';
describe('UsersService', () => {
let service: UsersService;
let repo: jest.Mocked<UserRepository>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersService,
{
provide: UserRepository,
useValue: {
save: jest.fn(),
findOne: jest.fn(),
find: jest.fn(),
},
},
],
}).compile();
service = module.get<UsersService>(UsersService);
repo = module.get(UserRepository);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('create', () => {
it('should save and return user', async () => {
const dto = { name: 'John', email: 'john@test.com' };
const expectedUser = { id: '1', ...dto };
repo.save.mockResolvedValue(expectedUser);
const result = await service.create(dto);
expect(result).toEqual(expectedUser);
expect(repo.save).toHaveBeenCalledWith(dto);
});
it('should throw on duplicate email', async () => {
repo.findOne.mockResolvedValue({ id: '1', email: 'test@test.com' });
await expect(
service.create({ name: 'Test', email: 'test@test.com' }),
).rejects.toThrow(ConflictException);
});
});
describe('findById', () => {
it('should return user when found', async () => {
const user = { id: '1', name: 'John' };
repo.findOne.mockResolvedValue(user);
const result = await service.findById('1');
expect(result).toEqual(user);
});
it('should throw NotFoundException when not found', async () => {
repo.findOne.mockResolvedValue(null);
await expect(service.findById('999')).rejects.toThrow(NotFoundException);
});
});
});
// Testing guards and interceptors
describe('RolesGuard', () => {
let guard: RolesGuard;
let reflector: Reflector;
beforeEach(async () => {
const module = await Test.createTestingModule({
providers: [RolesGuard, Reflector],
}).compile();
guard = module.get<RolesGuard>(RolesGuard);
reflector = module.get<Reflector>(Reflector);
});
it('should allow when no roles required', () => {
const context = createMockExecutionContext({ user: { roles: [] } });
jest.spyOn(reflector, 'getAllAndOverride').mockReturnValue(undefined);
expect(guard.canActivate(context)).toBe(true);
});
it('should allow admin for admin-only route', () => {
const context = createMockExecutionContext({ user: { roles: ['admin'] } });
jest.spyOn(reflector, 'getAllAndOverride').mockReturnValue(['admin']);
expect(guard.canActivate(context)).toBe(true);
});
});
function createMockExecutionContext(request: Partial<Request>): ExecutionContext {
return {
switchToHttp: () => ({
getRequest: () => request,
}),
getHandler: () => jest.fn(),
getClass: () => jest.fn(),
} as ExecutionContext;
}
```
Reference: [NestJS Testing](https://docs.nestjs.com/fundamentals/testing)