NestJS使用Jest测试方法之前访问私有类字段

时间:2020-07-28 12:14:20

标签: javascript unit-testing mocking jestjs nestjs

假设存在以下嵌套服务类,其中包含 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 私有类字段。 因为它是私有的,所以我无法在测试类中访问它。

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

1 个答案:

答案 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