HMilbradt
HMilbradt

Reputation: 4639

Unit testing a service with many dependencies in NestJS

When building API's in Nest, I often come across an issue where a particular API might need to make use of several Nest modules to do it's job. I'd like to know if there's a better way to structure my modules so that unit testing them is easier.

For example, imagine we have an OrderService. The OrderService makes use of a few different dependencies in order to do it's job:

For the sake of this example, let's just imagine each of these 4 dependencies to be it's own Nest module.

When it comes to unit testing the OrdersService, I'd then need to stub out 4 different dependencies. This seems like a lot more work than it should be, and so I realized there must be a better way.

One thing that I've tried doing is creating separate helper files for setting up each services mocks. This cuts down on the amount of boilerplate for each service that uses a particular dependency, but you still end up in a situation where 1 service might have 4 different dependencies.

Ideally, I'd like to implement some pattern or structure so that when I test a file, the dependencies are either really simple or automatic to mock, or a particular file only has 1 dependency at a time, without oversimplifying the system.

My question really boils down to:

How do you handle many dependencies like this in a Service, without ending up in a situation where testing a function requires you to mock 4+ methods. I'd love to hear a Nest specific way to do this, but I'd also appreciate any generic software engineering examples or patterns to look into as well.

Upvotes: 5

Views: 7218

Answers (1)

Jay McDoniel
Jay McDoniel

Reputation: 70570

There's a pull request to allow for auto-mocking with Nest's @nestjs/testing package, but it hasn't been accepted yet (working on it though!), and there's a package called @golevelup/ts-jest that allows you to set up mocks of an object very quickly and easily. So instead of having to define the entire { get: jest.fn(), create: jest.fn(), ...etc } useValue provider, you could have something as quick as

const modFixture = await Test.createTestingModule({
  providers: [
    OrderService,
    {
      provide: ProductService,
      useValue: createMock<ProductService>(),
    },
    {
      provide: UserService,
      useValue: createMock<UserService>(),
    },
    ...etc
  ]
}).compile();

And all of the methods will be set up as jest.fn() methods, that can be extended based on your specific test

Upvotes: 9

Related Questions