Skip to content

Testing NestJS Services

Services hold business rules, so they deserve focused unit tests. This lesson covers repository mocks, exception assertions, and arranging clear service scenarios.

Service Test Structure

Arrange mocks for repositories and collaborators, act by calling the service method, assert outcomes and interactions. Cover happy paths and intentional failure paths (not found, conflict, validation delegated upstream).

it('creates a cat', async () => {
  repo.save.mockResolvedValue({ id: 1, name: 'Milo' });
  await expect(service.create({ name: 'Milo' })).resolves.toEqual({ id: 1, name: 'Milo' });
  expect(repo.save).toHaveBeenCalledWith({ name: 'Milo' });
});

Assert both the returned value and that the repository was called with the expected payload.

Edge Cases to Prioritize

- missing entity -> NotFoundException
- duplicate unique field -> ConflictException
- unauthorized ownership -> ForbiddenException
- partial update merges fields correctly
  • Do not re-test ValidationPipe inside service unit tests—DTO validation belongs to pipe/e2e tests.
  • When services call other services, mock those collaborators.
  • Prefer dependency injection tokens that make swapping fakes easy.
  • Name tests after business behavior, not implementation details.

Service Testing Cheatsheet

High-value assertions for services.

Scenario Assert
Create Saved payload + returned entity
Read missing Throws NotFoundException
Update Loads, merges, saves
Delete Calls remove / affected count
Permission deny Throws ForbiddenException

Testing Transactions

If a service uses transactions, mock the transaction API and assert that rollback occurs when a step fails—or extract a unit that is easier to test and cover transactions in integration tests.

Time and IDs

Inject clocks or id generators when services depend on new Date() or random ids so tests stay deterministic.

Common Mistakes

  • Only testing happy paths.
  • Asserting Nest HTTP response objects inside service tests.
  • Using real databases for every service unit test.
  • Duplicating the same repository mock setup in every file without helpers.

Key Takeaways

  • Service tests mock persistence and assert business outcomes.
  • Cover not-found and conflict paths explicitly.
  • Leave DTO pipe validation to other test layers.
  • Keep scenarios named after business behavior.

Pro Tip

For each public service method, write at least one success test and one failure test before marking the feature done—it's a cheap safety net.