๐ŸงชTesting Strategies

Gain confidence in your code through rigorous testing strategies from unit to end-to-end.

๐Ÿงซ Unit Testing with Jest

Welcome to the world of unit testing in NestJS! In this section, we'll explore how to write effective unit tests using Jest. Unit testing is a crucial part of modern software development, ensuring that your code works as expected and catches issues early.

๐Ÿ’ก Why Unit Testing?

  • Catch bugs early in the development process
  • Ensure code behaves as expected under different scenarios
  • Support test-driven development (TDD) workflows
  • Provide documentation for how your code should work

โœ… Setting Up Jest in a NestJS Project

First, ensure you have the necessary dependencies installed:

npm install --save-dev jest ts-jest @types/jest @nestjs/jest

Create a Jest configuration file ( jest.config.ts ) in your project root:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  globals: {
    'ts-jest': {
      tsConfigFile: './tsconfig.json'
    }
  },
  transformIgnorePatterns: ['<rootDir>/node_modules/']
};

๐Ÿ’ก Writing Unit Tests in Jest

Each service should have a corresponding test file. For example, for src/users/services/user.service.ts , create src/users/services/user.service.spec.ts .

โœ… Key Jest Concepts

  • describe() : Groups tests together
  • it() : Defines individual test cases
  • beforeAll(), beforeEach(), afterAll(), afterEach() : Lifecycle hooks for setup and cleanup
  • expect() : Asserts expectations about values

๐Ÿ’ก Mocking Dependencies

When writing unit tests, you want to isolate the code under test from its dependencies. This is where mocking comes in.

  • Manual mocks : Create mock implementations directly in your test file
  • Jest mock utilities : Use jest.mock() and Mock functions

โœ… Test Spies and Assertions

Jest provides powerful tools for spying on function calls and making assertions.

it('should call the repository save method', async () => {
  const mockUser = { id: 1, email: 'test@example.com' };
  
  jest.spyOn(userRepository, 'save').mockResolvedValue(mockUser);
  
  const result = await userService.createUser(mockUser);
  
  expect(userRepository.save).toHaveBeenCalledWith(mockUser);
  expect(result).toEqual(mockUser);
});

๐Ÿ’ก Snapshot Testing

Snapshot testing is useful for verifying that your components render correctly. While more common in UI testing, it can also be used for service layer testing.

it('should return the correct user object', () => {
  const mockUser = { id: 1, email: 'test@example.com' };
  
  jest.spyOn(userRepository, 'findOne').mockResolvedValue(mockUser);
  
  const result = await userService.findOne(1);
  
  expect(result).toMatchSnapshot();
});

โœ… Best Practices for Unit Testing

  • Test one thing at a time
  • Use descriptive test names that explain what is being tested
  • Keep tests independent and isolated
  • Mock external dependencies thoroughly
  • Write tests before writing the code (TDD approach)

โŒ Common Pitfalls to Avoid

  • Don't test implementation details, focus on behavior
  • Don't skip writing tests for edge cases
  • Avoid over-mocking - keep your mocks realistic
  • Don't forget to clean up after tests using afterEach() or afterAll()

๐Ÿ’ก Real-World Example

// src/auth/services/jwt.service.ts
export class JwtService {
  sign(payload: object, options?: SignOptions): string;
  verify(token: string, options?: VerifyOptions): Promise<object>;
}

// src/auth/services/jwt.service.spec.ts
import { JwtService } from './jwt.service';

describe('JwtService', () => {
  const mockPayload = { id: 1, email: 'test@example.com' };
  
  beforeEach(() => {
    // Setup any common mocks or state here
  });
  
  describe('sign method', () => {
    it('should return a valid JWT token', () => {
      const jwtService = new JwtService();
      const token = jwtService.sign(mockPayload);
      
      expect(token).toBeDefined();
      // Additional assertions as needed
    });
  });
  
  describe('verify method', () => {
    it('should correctly verify a valid token', async () => {
      const jwtService = new JwtService();
      const token = jwtService.sign(mockPayload);
      
      const result = await jwtService.verify(token);
      
      expect(result).toEqual(mockPayload);
    });
  });
});

๐Ÿš€ End-to-End Testing

Quiz

Question 1 of 5

What is the purpose of unit testing in a NestJS application?

  • To test API endpoints with real HTTP requests
  • To ensure individual components work as expected in isolation
  • To test user interface interactions
  • To perform end-to-end testing