单元测试Nest.js中的Mock Injected Twilio服务



我在nest.js应用程序中重写提供程序/设置模块测试以进行测试时遇到问题。

模块文件:smsModule.ts:

import { TwilioService } from './twilio/twilio.service';
import { DynamicModule, Module } from '@nestjs/common';
import { TwilioConfig, SMS_TWILIO_CONFIG } from './twilio.config';
import { TwilioClientCustom } from './twilio/twilio-client-custom';
@Module({
imports: [],
providers: [TwilioService],
})
export class SmsModule {
static register(options: TwilioConfig): DynamicModule {
return {
module: SmsModule,
imports: [HttpModule],
providers: [
{
provide: SMS_TWILIO_CONFIG,
useValue: options,
},
TwilioService,
TwilioClientCustom,
],
exports: [TwilioService],
};
}
}

Twilio客户端,配置文件:

//client
import { TwilioConfig, SMS_TWILIO_CONFIG } from '../twilio.config';
import { Twilio } from 'twilio';
import { Inject, Injectable } from '@nestjs/common';
@Injectable()
export class TwilioClientCustom extends Twilio {
constructor(@Inject(SMS_TWILIO_CONFIG) twilioConfig: TwilioConfig) {
super(twilioConfig.accountSid, twilioConfig.authToken);
}
}

//config 
import { IsString, IsNotEmpty, NotContains, IsOptional, IsArray } from 'class-validator';
const INFO = 'Must be ....';
export class TwilioConfig {
@IsString()
@IsNotEmpty()
@NotContains('OVERRIDE_WITH_', { message: INFO })
accountSid: string;
@IsString()
@IsNotEmpty()
authToken: string;
@IsArray()
@IsOptional()
@IsNotEmpty('OVERRIDE_WITH_', { message: INFO })
serviceSid: string;
}
export const SMS_TWILIO_CONFIG = 'smsTwilioConfig';

Twilio服务文件:Twilio.service.tst:

import { HttpService } from '@nestjs/axios';
import { TwilioConfig, SMS_TWILIO_CONFIG } from '../twilio.config';
import { SendSmsTwilioService } from './../sendsms.service';
import { Inject, Injectable } from '@nestjs/common';
import { TwilioClientCustom } from './twilio-client-custom';
@Injectable()
export class TwilioService implements SendSmsTwilioService {
constructor(
@Inject(SMS_TWILIO_CONFIG) private readonly config: TwilioConfig,
private readonly client: TwilioClientCustom,
private readonly httpService: HttpService
) {}
async sendSMS(to: string, from: string, body: string): Promise<string> {
......
return this.client.messages
.create({
to, //Recipinet's number
from, //Twilio number
body, //Messages to Recipient
})
.then((message) => message.sid)
.catch(() => {
throw new Error('TWILIO accountSid or authToken not valid');
});
}

我想测试我的服务:测试文件:

import { Test, TestingModule } from '@nestjs/testing';
//import { TWILIO_CONFIG_SPEC } from './test.config';
import { TwilioClientCustom } from '../src/twilio/twilio-client-custom';
import { HttpService } from '@nestjs/axios';
import { TwilioConfig } from './../src/twilio.config';
import { TwilioService } from './../src/twilio/twilio.service';
import nock from 'nock';
describe('TwilioService', () => {
let service: TwilioService;
let client: TwilioClientCustom;
let httpService: HttpService;
afterEach(() => {
nock.cleanAll();
});
//const smsServiceMock = {};
beforeEach(async () => {
const moduleRef: TestingModule = await Test.createTestingModule({
providers: [
TwilioService,
{
provide: HttpService,
useValue: {
method1: jest.fn(),
method2: jest.fn(),
method3: jest.fn(),
},
},
TwilioService,
],
imports: [
NestConfigModule.forRoot({
config: TwilioConfig,
} as Record<string, unknown>),
],
}).compile();
//getting service module from main module
httpService = moduleRef.get<HttpService>(HttpService);
client = moduleRef.get<TwilioClientCustom>(TwilioClientCustom);
service = moduleRef.get<TwilioService>(TwilioService);
});
//check service is avaible
it('Should be defined', () => {
expect(client).toBeDefined();
expect(service).toBeDefined();
expect(httpService).toBeDefined();
});

运行测试后,我得到以下错误:

Nest can't resolve dependencies of the TwilioService (?, TwilioClientCustom, HttpService). Please make sure that the argument smsTwilioConfig at index [0] is available in the RootTestModule context.
Potential solutions:
- If smsTwilioConfig is a provider, is it part of the current RootTestModule?
- If smsTwilioConfig is exported from a separate @Module, is that module imported within RootTestModule?
@Module({
imports: [ /* the Module containing smsTwilioConfig */ ]
})

我该如何解决这个问题?

smsTwilioConfig通过SmsModule.register(opts)向Nest的IOC注册。

然而,您似乎正在尝试使用createTestingModule直接测试TwilioService。这很好,但这确实意味着你需要在测试中包含带有提供者或导入的配置。我的猜测是,您认为NestConfigModule...会这样做,但这并没有将配置设置在正确的级别。

我认为以下是正确的方向

const moduleRef: TestingModule = await Test.createTestingModule({
providers: [
TwilioService,
{
provide: HttpService,
useValue: {
method1: jest.fn(),
method2: jest.fn(),
method3: jest.fn(),
},
},
{
// added this
provide: SMS_TWILIO_CONFIG,
useValue: testConfig
},
],
imports: [
// removed NestConfigModule
],
}).compile();

最新更新