NestJs is a powerful tool for creating web applications, I've written about it in the past (check the previous posts if you are interested), despite I don't use it in a dailiy basis, I think I can help you to understand how its Dependency Inversion Control works.

I'm going to explain it with a simple example: A simple module which reads client information using an external module which provides a DB connection

Suppose you already have a Module called DatabseModule which declares a provider named DatabaseService, also this Service is exported in the module.

So, you want to use the DatabaseService in another module: UserModule. This module needs two different database connections, here is where dynamic module injection via params appears.

Module & Service preparation

import { Injectable, Inject } from '@nestjs/common';
 import PouchDB from 'pouchdb';

 @Injectable()
 export class PouchService {
     private remotedb: PouchDB.Database

     constructor(@Inject('DATABASE') private database) {
         this.remotedb = new PouchDB('http://endpoint.com/' + database)
     }
 }
pouchdb.service.ts - DatabaseService implementation

With the prevous snippet we've created a simple DatabaseService wich its constructor awaits a string, the database name. Because we're using pouchDB in the example, we need to stablish a new connection for each database we want to use. (PouchDB is a NO-SQL database).

The interesting part in the code is the @Inject annotation, with it, NestJS injects the property 'DATABASE' into the constructor.

For the second part, we need to provide that value, we will do it in the top level, in the Module itself. The way for making this module more flexible, is to create a static method called register() or forRoot() which has the database string as parameter, and then return the DatabaseModule with the DatabaseService properly configured for the given database:

import { Module, DynamicModule } from '@nestjs/common';
import { PouchService } from './pouch/pouch.service';

 @Module({
   providers: [PouchService]
 })
 export class DatabaseModule {
     static register(database: string): DynamicModule {
         return {
             module: null,
             providers: [
                 {
                     provide: 'DATABASE',
                     useValue: database
                 },
                 PouchService
             ],
             exports: []
         }
     }
 }
DatabaseModule with a static method register for dynamic service generation

Now let's code the test scaffold for implementing Jest tests

The trick is so simple, we need to modify the createTestingModule() function and specify the parameter we want to initialize the service to be tested:

import { Test, TestingModule } from '@nestjs/testing';
import { PouchService } from './pouch.service';

describe('PouchService', () => {
  let service: PouchService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        {
          provide: PouchService,
          useValue: new PouchService('tenants'),
        }
      ],
    }).compile();

    service = module.get<PouchService>(PouchService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  it('should return info', async () => {
    const info = await service.info()
    expect(info).toBeDefined()
  })
});