I am getting issues while unit testing my controller and getting an error "Nest can't resolve dependencies of my service".
For maximum coverage I wanted to unit test controller and respective services and would like to mock external dependencies like mongoose connection. For the same I already tried suggestions mentioned in the below link but didn't find any luck with that:
https://github.com/nestjs/nest/issues/194#issuecomment-342219043
Please find my code below:
export const deviceProviders = [
{
provide: 'devices',
useFactory: (connection: Connection) => connection.model('devices', DeviceSchema),
inject: ['DbConnectionToken'],
},
];
export class DeviceService extends BaseService {
constructor(@InjectModel('devices') private readonly _deviceModel: Model<Device>) {
super();
}
async getDevices(group): Promise<any> {
try {
return await this._deviceModel.find({ Group: group }).exec();
} catch (error) {
return Promise.reject(error);
}
}
}
@Controller()
export class DeviceController {
constructor(private readonly deviceService: DeviceService) {
}
@Get(':group')
async getDevices(@Res() response, @Param('group') group): Promise<any> {
try {
const result = await this.deviceService.getDevices(group);
return response.send(result);
}
catch (err) {
return response.status(422).send(err);
}
}
}
@Module({
imports: [MongooseModule.forFeature([{ name: 'devices', schema: DeviceSchema }])],
controllers: [DeviceController],
components: [DeviceService, ...deviceProviders],
})
export class DeviceModule { }
Unit test:
describe('DeviceController', () => {
let deviceController: DeviceController;
let deviceService: DeviceService;
const response = {
send: (body?: any) => { },
status: (code: number) => response,
};
beforeEach(async () => {
const module = await Test.createTestingModule({
controllers: [DeviceController],
components: [DeviceService, ...deviceProviders],
}).compile();
deviceService = module.get<DeviceService>(DeviceService);
deviceController = module.get<DeviceController>(DeviceController);
});
describe('getDevices()', () => {
it('should return an array of devices', async () => {
const result = [{
Group: 'group_abc',
DeviceId: 'device_abc',
},
{
Group: 'group_xyz',
DeviceId: 'device_xyz',
}];
jest.spyOn(deviceService, 'getDevices').mockImplementation(() => result);
expect(await deviceController.getDevices(response, null)).toBe(result);
});
});
});
When I am running my test case above, I am getting two errors:
Nest can't resolve dependencies of the DeviceService (?). Please make sure that the argument at index [0] is available in the current context.
Cannot spyOn on a primitive value; undefined given
Mocking is a process used in unit testing when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies.
The main objective of unit testing is to isolate written code to test and determine if it works as intended. Unit testing is an important step in the development process, because if done correctly, it can help detect early flaws in code which may be more difficult to find in later testing stages.
Correct. You should mock things that depend on anything persistent or external in order to prevent the test from depending on anything persistent or external.
Example code:
import { Test } from '@nestjs/testing';
import { getModelToken } from '@nestjs/mongoose';
describe('auth', () => {
let deviceController: DeviceController;
let deviceService: DeviceService;
const mockRepository = {
find() {
return {};
}
};
beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [DeviceModule]
})
.overrideProvider(getModelToken('Auth'))
.useValue(mockRepository)
.compile();
deviceService = module.get<DeviceService>(DeviceService);
});
// ...
});
You are not injecting the correct token here. Instead of a plain string you have to use the function getModelToken
.
import { getModelToken } from '@nestjs/mongoose';
// ...
{ provide: getModelToken('devices'), useFactory: myFactory },
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With