Jest กับ NestJS และฟังก์ชัน async

Aug 18 2020

ฉันพยายามที่จะมีการทดสอบฟังก์ชั่น async ของserviceในnestJS

ฟังก์ชันนี้เป็น async ... โดยทั่วไปจะได้รับค่า (JSON) จากฐานข้อมูล (โดยใช้ที่เก็บ - TypeORM) และเมื่อรับข้อมูลสำเร็จ "แปลง" เป็นคลาสอื่น (DTO) ... การนำไปใช้:

async getAppConfig(): Promise<ConfigAppDto> {
  return this.configRepository.findOne({
    key: Equal("APPLICATION"),
  }).then(config => {
    if (config == null) {
      return new class implements ConfigAppDto {
        clientId = '';
        clientSecret = '';
      };
    }
    return JSON.parse(config.value) as ConfigAppDto;
  });
}

โดยใช้คอนโทรลเลอร์ฉันตรวจสอบแล้วว่าใช้งานได้ดี ตอนนี้ฉันกำลังพยายามใช้ Jest เพื่อทำการทดสอบ แต่ไม่ประสบความสำเร็จ ... ปัญหาของฉันคือวิธีการจำลองfindOneฟังก์ชันจากrepository..

แก้ไข : ฉันพยายามใช้@golevelup/nestjs-testingเพื่อล้อเลียนRepository!

ฉันล้อเลียนไปแล้วrepositoryแต่ด้วยเหตุผลบางอย่างresolveก็ไม่เคยเรียก ..

describe('getAppConfig', () => {
  const repo = createMock<Repository<Config>>();

  beforeEach(async () => {
    await Test.createTestingModule({
      providers: [
        ConfigService,
        {
          provide: getRepositoryToken(Config),
          useValue: repo,
        }
      ],
    }).compile();
  });

  it('should return ConfigApp parameters', async () => {
    const mockedConfig = new Config('APPLICATION', '{"clientId": "foo","clientSecret": "bar"}');
    repo.findOne.mockResolvedValue(mockedConfig);
    expect(await repo.findOne()).toEqual(mockedConfig); // ok

    const expectedReturn = new class implements ConfigAppDto {
      clientId = 'foo';
      clientSecret = 'bar';
    };
    expect(await service.getAppConfig()).toEqual(expectedReturn);

    // jest documentation about async -> https://jestjs.io/docs/en/asynchronous
    // return expect(service.getAppConfig()).resolves.toBe(expectedReturn);
  });
})
  • expect(await repo.findOne()).toEqual(mockedConfig);การทำงานที่ดี;
  • expect(await service.getAppConfig()).toEqual(expectedReturn);หมดเวลา => Async callback was not invoked within the 5000 ms timeout specified by jest.setTimeout;

เมื่อใช้การดีบักฉันเห็นว่าservice.getAppConfig()มีการเรียกใช้repository.findOne()เช่นกัน แต่.thenพื้นที่เก็บข้อมูลของ findOne ไม่เคยถูกเรียก

อัปเดต : ฉันกำลังพยายามจำลองที่เก็บโดยใช้@golevelup/nestjs-testingและด้วยเหตุผลบางประการผลลัพธ์ที่เยาะเย้ยไม่สามารถใช้งานได้ในบริการ ถ้าฉันเยาะเย้ยพื้นที่เก็บข้อมูลโดยใช้เพียงjest(เช่นรหัสด้านล่าง) ผลงานการทดสอบ ... @golevelup/nestjs-testingดังนั้นผมคิดว่าปัญหาที่แท้จริงของฉันมันเป็น

...
provide: getRepositoryToken(Config),
useValue: {
  find: jest.fn().mockResolvedValue([new Config()])
},
...

คำตอบ

2 RobertoCorreia Aug 21 2020 at 22:25

ดังนั้นปัญหาที่แท้จริงของฉันคือการล้อเลียนRepositoryต่อNestJSไปอย่างไร ด้วยเหตุผลบางอย่างเมื่อฉันล้อเลียนโดยใช้@golevelup/nestjs-testingสิ่งแปลก ๆ ก็เกิดขึ้น!

ฉันไม่พบเอกสารที่ดีเกี่ยวกับเรื่องนี้จริงๆ@golevelup/nestjs-testingดังนั้นฉันจึงเลิกใช้มัน

ทางออกของฉันสำหรับคำถามคือใช้เท่านั้นJestและNestJSฟังก์ชัน ... รหัสผลลัพธ์คือ:

บริการ :

// i'm injecting Connection because I need for some transactions later;
constructor(@InjectRepository(Config) private readonly configRepo: Repository<Config>, private connection: Connection) {}

async getAppConfig(): Promise<ConfigApp> {
  return this.configRepo.findOne({
    key: Equal("APPLICATION"),
  }).then(config => {
    if (config == null) {
      return new ConfigApp();
    }
    return JSON.parse(config.value) as ConfigApp;
  })
}

ทดสอบ :

describe('getAppConfig', () => {
  const configApi = new Config();
  configApi.key = 'APPLICATION';
  configApi.value = '{"clientId": "foo", "clientSecret": "bar"}';

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        ConfigAppService,
        {
          provide: getRepositoryToken(Config),
          useValue: {
            findOne: jest.fn().mockResolvedValue(new
            Config("APPLICATION", '{"clientId": "foo", "clientSecret": "bar"}')),
          },
        },
        {
          provide: getConnectionToken(),
          useValue: {},
        }
      ],
    }).compile();

    service = module.get<ConfigAppService>(ConfigAppService);
  });

  it('should return ConfigApp parameters', async () => {
    const expectedValue: ConfigApp = new ConfigApp("foo", "bar");

    return service.getAppConfig().then(value => {
      expect(value).toEqual(expectedValue);
    })
  });
})

บางแหล่งที่ใช้สำหรับโซลูชันนี้: https://github.com/jmcdo29/testing-nestjs/tree/master/apps/typeorm-sample

1 Leo Aug 18 2020 at 19:53

ฉันคิดว่าได้expect(await repo.findOne()).toEqual(mockedConfig);ผลเพราะคุณล้อเลียนมันจึงกลับมาทันที ในกรณีนี้expect(await service.getAppConfig()).toEqual(expectedReturn);คุณไม่ได้เยาะเย้ยมันดังนั้นอาจต้องใช้เวลามากกว่านี้ดังนั้นitฟังก์ชันจึงกลับมาก่อนที่จะได้รับการPromiseแก้ไขอย่างสมบูรณ์

getAppConfig()ความคิดเห็นที่คุณโพสต์จากเอกสารความตลกขบขันควรทำเคล็ดลับถ้าคุณเยาะเย้ยการเรียกร้องให้

service.getAppConfig = jest.fn(() => Promise.resolve(someFakeValue))

หรือ

spyOn(service, 'getAppConfig').and.mockReturnValue(Promise.resolve(fakeValue))