【问题标题】:Typescript/Jest mocking a shared function from a serviceTypescript/Jest 模拟服务中的共享功能
【发布时间】:2021-11-19 20:36:06
【问题描述】:

我有一个 NestJS 服务,但这并不是一个 NestJS 问题。但是,NestJS 测试正在发挥作用,我使用它来创建用于测试等的服务。我的服务用于进行多次调用,并返回所有数据。

在我的场景中,有一个服务 (myservice) 将获得一些结果(一个数据对象),它结合了来自各种来源的结果。外部源都是基于 Promise(async/await)的,用于获取所有不同的数据点,将其结合到 myservice(由其他人扩展的基础服务)中,以结合错误处理、promise 结果处理等.

我在尝试模拟外部测试调用时遇到问题。我的问题是从 NodeJS 读取数据的函数。我可以毫无问题地自行测试该函数,但现在我试图在我的服务中模拟这个函数调用。

问题中的函数的简短示例,作为以下内容的一部分: 我的服务.ts

public async GetData(DataType: number = DATA_TYPES.TEXT): Promise<ResultFile> {
    const ResultData: ResultFile = new ResultFile(DataType);

    return new Promise<ResultFile>((resolve, reject) => {
        const Data$: Promise<string> = this.GetResultFileContents();
        const StatusCode$: Promise<number> = this.GetResultFileStatusCode();

        Promise.all([Data$, StatusCode$])
            .then((Results) => {
                ResultData.Contents = Results[0]; // Promise returns a string
                ResultData.StatusCode = Results[1]; // Promise returns a number

                resolve(ResultData);
            })
            .catch((Exception: Error) => {
                ResultData.StatusCode = HttpStatus.NOT_FOUND;
                ResultData.Contents = Exception.message;
                reject(ResultData);
            });
    });
}

以上是尝试检索不同数据的主要方法。这比现有的 2 个承诺更多,但有两个会显示我的问题。

public async GetResultFileContents(): Promise<string> {
    try {
        const Results$: string = await ReadFileContents(this.Directory_, this.BaseName_);
        return Results$;
    } catch (Exception) {
        throw new HttpException(`File not found: ${this.BaseName_} in ${this.Directory_}`, HttpStatus.NOT_FOUND);
    }
}

public async GetResultFileStatusCode(): Promise<number> {
    let StatusCode: number = 0;
    try {
        const StatusCodeFile: string = `${this.BaseName_}.err`;
        const StatusCodeData$ = await ReadFileContents(this.Directory_, StatusCodeFile);
        StatusCode = GetIntegerFromText(StatusCodeData$);
    } catch (Exception) {
        StatusCode = HttpStatus.OK; // Return OK since a specific status was not set to be returned.
    }
    return new Promise<number>((resolve) => {
        resolve(StatusCode);
    });
}

为了返回 Promise 而调用的两个方法都使用了外部函数 ReadFileContents()。这是我要模拟的函数,因为它可以将数据作为字符串返回,或者抛出异常,为包含数据的文件包装操作系统检查(除其他外)。

这个函数很常见,并且被许多从文件系统读取数据的方法所共享。还有一些类似于 REST 调用的东西,也有同样的问题,但这是一个简单的例子。

我的问题现在出现在测试文件中。虽然我可以测试服务以及myservice.ts 中的方法,但我不知道如何模拟对 ReadFileContents() 的外部调用以确保myservice.ts 中的方法正确执行。

我想测试不同的返回字符串,以及文件不存在时的异常捕获等

我的测试:

import { Test, TestingModule } from '@nestjs/testing';

import { MyService } from './my.service';

// TODO: Need to mock the internal calls to ReadFileContents() to throw exceptions
describe('MyService (mock)', () => {
    let service: MyService;

    afterEach(() => {});

    beforeEach(async () => {
        const module: TestingModule = await Test.createTestingModule({
            providers: [MyService],
        }).compile();

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

    it('should be defined', () => {
        expect(service).toBeDefined();
    });

    it('should handle exceptions when reading missing .hdr file', async () => {
        // const mockReadFileContents = jest.spyOn(service.???);
    });
});

在最后一个函数中,我不知道如何模拟 ReadFileContents,因为它只是服务中的一个函数,位于另一个源文件中。

我真的不想在服务中创建一个公共方法,只是简单地调用这个函数,所以我可以模拟它,如果我能帮忙的话。

请忽略缺少的功能或其他拼写错误,因为这是一个快速编辑,以提供我正在尝试完成的示例。

【问题讨论】:

    标签: typescript unit-testing jestjs nestjs


    【解决方案1】:

    我一直在努力,但无法让模拟工作。然后我确实更改了我试图模拟的函数,使其位于另一个服务 (fsService) 中,并通过具有依赖注入的构造函数在 myService 中使用此服务。

    constructor(
        private FileSystem_: fsService,
    ) {}
    

    然后可以通过模拟服务、提供虚假定义 ({provide: fsService, useClass: fsServiceMock }) 等在测试中轻松模拟。

    import { Test, TestingModule } from '@nestjs/testing';
    import { MyService } from './my.service';
    import { FsService } from './fs.service';
    
    describe('MyService (mock)', () => {
        let service: MyService;
        let FSService_: FsService;
    
        afterEach(() => {
            jest.resetAllMocks();
        });
    
        beforeEach(async () => {
            const module: TestingModule = await Test.createTestingModule({
                providers: [
                    FSService,
                    MyService,
                ],
            }).compile();
            FsService_ = module.get<FSService>(FSService);
            service = module.get<MyService>(MyService);
        });
    
        it('should be defined', () => {
            expect(service).toBeDefined();
        });
    
        it('should handle exceptions when reading missing .hdr file', async () => {
            FSService_.ReadFileContents = jest.fn().mockRejectedValue(new Error('ENOENT: File not Found'));
            ...
        });
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-22
      • 2019-07-16
      • 2021-06-28
      • 2020-06-01
      • 2023-01-30
      • 2019-08-28
      • 2022-10-25
      • 1970-01-01
      相关资源
      最近更新 更多