假设存在以下嵌套服务类,其中包含 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 。 第一种情况:如果条件为真。第二种情况:如果条件为假。
以下是缺少两个测试的测试类:
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 私有类字段。 因为它是私有的,所以我无法在测试类中访问它。
我的问题是:实现这一目标的最佳和正确方法是什么?
答案 0 :(得分:2)
如果您只是想模拟它,可以随时使用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');
});
});
现在您可以不使用jest.spyOn(cache, 'get')
来呼叫as any
。