假设有以下嵌套服务类,带有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')
。