NestJS在用jest测试方法之前访问私有类字段



假设有以下嵌套服务类,带有private字段myCache和公共方法myFunction

import * as NodeCache from 'node-cache'
class MyService{
private myCache = new NodeCache();
myFunction() {
let data = this.myCache.get('data');
if(data === undefined){
// get data with an http request and store it in this.myCache with the key 'data'
} 
return data;
}
}

我想针对两种不同的情况测试函数myFunction。第一种情况:如果条件成立。第二种情况:如果条件为false。

以下是缺少两个测试的测试类:

import { Test, TestingModule } from '@nestjs/testing';
import { MyService} from './myService';
describe('MyService', () => {
let service: MyService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [MyService],
}).compile();
service = module.get<MyService>(MyService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('myFunction', () => {
it('should return chached data', () => {
// first test
}),
it('should return new mocked data', () => {
// second test
})
})
});

因此,我想我必须访问或模拟myCache私有类字段因为它是私有的,所以我无法在测试类中访问它。

我的问题是:实现这一目标的最佳和正确的方法是什么?

如果您只是想模拟它,您可以始终使用as any告诉Typescript不要警告您访问私有值。

jest.spyOn((service as any).myCache, 'get').mockReturnValueOnce(someValue);

然而,不得不一次又一次地这样做有点烦人,而且这并不是最好的做法。相反,我要做的是将您的缓存移动为可注入的提供程序,这样它就可以在接到通知后立即交换,并且您的MyService不再对node-cache有硬依赖。类似这样的东西:

// my.module.ts
@Module({
providers: [
MyService,
{
provide: 'CACHE',
useClass: NodeCache
}
]
})
export class MyModule {}
// my.service.ts
@Injectable()
export class MyService {
constructor(@Inject('CACHE') private readonly myCache: NodeCache) {}
...

现在,在测试中,您可以将CACHE令牌交换为模拟实现,该实现也可以在beforeEach块中检索,这意味着不再有任何实现。

describe('MyService', () => {
let service: MyService;
let cache: { get; set; }; // you can change the type here

beforeEach(async () => {
const modRef = await Test.createTestingModule({
providers: [
MyService,
{
provide: 'CACHE',
useValue: { get: jest.fn(), set: jest.fn() }
}
]
}).compile();
service = modRef.get(MyService);
cache = modRef.get<{ get; set; }>('CACHE');
});
});

现在您可以在不使用as any的情况下调用jest.spyOn(cache, 'get')

最新更新