简体   繁体   English

Typescript/Jest mocking 来自服务的共享 function

[英]Typescript/Jest mocking a shared function from a service

I have a service for NestJS, but this is not really a NestJS issue.我有一个 NestJS 服务,但这并不是真正的 NestJS 问题。 However, NestJS testing is in play, and I use it to create the service for testing, etc. My service is used to make a number of calls, and return all the data.然而,NestJS 测试正在进行中,我用它来创建测试服务等。我的服务用于进行多次调用,并返回所有数据。

In my scenario, there is a service (myservice) which will get some results (an object of data) that combines results from various sources.在我的场景中,有一个服务 (myservice) 将获得一些结果(object 的数据),它结合了来自各种来源的结果。 The external sources are all Promise (async/await) based, and are used to get all the different data points, combine this into the myservice (a base service that is extended by others) to combine the error handling, promise result processing, etc.外部源都是基于 Promise (async/await),用于获取所有不同的数据点,将其组合到 myservice(由其他人扩展的基础服务)以组合错误处理,promise 结果处理等.

I am having an issue trying to mock the external calls for testing.我在尝试模拟外部测试调用时遇到问题。 My issue is for the function that reads data from NodeJS.我的问题是从 NodeJS 读取数据的 function。 I can test the function on its own without issue, but now I am trying to mock out this function call in my service.我可以毫无问题地自行测试 function,但现在我正试图在我的服务中模拟这个 function 调用。

A short sample of the functions in questions, as part of: myservice.ts问题中的函数的简短示例,作为 myservice.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);
            });
    });
}

The above is the main method trying to retrieve different data.以上是尝试检索不同数据的主要方法。 This calls more promises than the 2 that are there, but two will show my issue.这调用的承诺比那里的 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);
    });
}

The two methods that are called, to return promises, both use an external function, ReadFileContents().被调用的两个方法返回承诺,都使用外部 function,ReadFileContents()。 This is the function I want to mock, as it can return the data as a string, or throw an exception, wrapping the OS checks (among other things) for the file(s) containing the data.这是我想要模拟的 function,因为它可以将数据作为字符串返回,或者抛出异常,为包含数据的文件包装操作系统检查(除其他外)。

This function is common, and shared by a number of the methods that read data from the file system.这个 function 是通用的,并且由许多从文件系统读取数据的方法共享。 There is also something similar to REST calls, which have the same issue, but this is a simple example.还有一些类似于 REST 调用的东西,它们有同样的问题,但这是一个简单的例子。

My issue now comes in the test file.我的问题现在出现在测试文件中。 While I can test the service, and the methods within the myservice.ts , but I do not know how to mock the external call to ReadFileContents() to ensure my methods in the myservice.ts are executing properly.虽然我可以测试服务和myservice.ts中的方法,但我不知道如何模拟对 ReadFileContents() 的外部调用以确保我在myservice.ts中的方法正确执行。

I want to test different return strings, as well as the catch of exceptions when files do not exist, etc.我想测试不同的返回字符串,以及文件不存在时的异常捕获等。

My test:我的测试:

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.???);
    });
});

In the last function, I do not know how to mock the ReadFileContents, as it is just a function within the service, which is in another source file.在最后一个 function 中,我不知道如何模拟 ReadFileContents,因为它只是服务中的一个 function,它位于另一个源文件中。

I really do not want make a public method in the service, to simply call this function, so I can mock it, if I can help that.我真的不想在服务中创建一个公共方法,只是调用这个 function,所以我可以模拟它,如果我能帮忙的话。

Please ignore missing functions, or other typos as this was a quick edit to provide the sample of what I am trying to accomplish.请忽略缺失的功能或其他拼写错误,因为这是一个快速编辑以提供我正在尝试完成的示例。

I have continued to work on this, and could not get the mock to work.我一直在为此努力,但无法让模拟工作。 I did then change the functions I was trying to mock, to be in another service (fsService) and used this service in the myService, via the constructor with Dependency Injection.然后我确实更改了我试图模拟的功能,使其位于另一个服务 (fsService) 中,并通过具有依赖注入的构造函数在 myService 中使用该服务。

constructor(
    private FileSystem_: fsService,
) {}

This can then be easily mocked in a test by either mocking the service, providing a fake definition ( {provide: fsService, useClass: fsServiceMock }) etc.然后可以通过 mocking 服务在测试中轻松模拟,提供虚假定义({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'));
        ...
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM