【问题标题】:Cover abstract class method with tests in Jest用 Jest 中的测试覆盖抽象类方法
【发布时间】:2020-03-12 08:04:36
【问题描述】:

我有一个抽象的通用服务类。

export default abstract class GenericService<Type> implements CrudService<Type> {
    private readonly modifiedUrl: URL;

    public constructor(url: string) {
        this.modifiedUrl = new URL(url, window.location.href);
    }

    public async get(path?: string, filter?: URLSearchParams): Promise<Type> {
        try {
            if (path) {
                this.modifiedUrl.href += `${path}`;
            }
            addQueryParams(this.modifiedUrl, filter);

            const response = await handleRequest(`${this.modifiedUrl}`, getFetchOptions('GET'));
            const data = await response.json();
            return (await data.data) ? data.data : data;
        } catch (error) {
            throw new Error(`Runtime error: ${error}`);
        }
    }
}

export async function handleRequest(input: RequestInfo, init: RequestInit): Promise<Response> {
    const response = await fetch(input, init);

    if (!response.ok) {
        throw new Error(`Network response was not ok: ${response}`);
    }

    return response;
}

我需要用测试覆盖这个GenericServiceget 方法。我试过这个:

jest.mock('../../components/crudTable/service/GenericService');
const genericService = GenericService;

export class DummyClass {
    public name: string = '';
}
export class DummyService extends GenericService<DummyClass> {}

describe('Generic Service', () => {
    it('1- spy prototype function', async () => {
        const spy = jest.spyOn(genericService.prototype, 'get');
        await genericService.prototype.get();
        expect(spy).toHaveBeenCalledTimes(1);
    });
    it('2- mock prototype function', async () => {
        const mockFn = jest.fn(genericService.prototype.get);
        await mockFn();
        expect(mockFn).toHaveBeenCalledTimes(1);
    });
    it('3- mock subclass function', async () => {
        const dummyService = new DummyService('test url');
        const mockFn = jest.fn(dummyService.get);
        await mockFn();
        expect(mockFn).toHaveBeenCalledTimes(1);
    });
});

此测试有效,但覆盖率统计显示它仍未被覆盖。 那么如何隐藏GenericService的所有get方法呢?

【问题讨论】:

    标签: javascript typescript jestjs


    【解决方案1】:

    你可以考虑以下方法

    GenericService.spec.js
    import GenericSerice from "./GenericService";
    
    class DummyService extends GenericSerice {}
    
    describe("GenericSerice", () => {
      beforeAll(() => {
        global.fetch = jest.fn();
      });
    
      describe("extended by a class", () => {
        let instance;
        beforeAll(() => {
          instance = new DummyService();
        });
    
        describe("method get", () => {
          describe("with path given", () => {
            const mockPath = "/pa/th";
    
            describe("receiving successful response", () => {
              let result;
              const mockData = { key: "mock value" };
              beforeAll(async () => {
                global.fetch.mockClear();
                global.fetch.mockResolvedValue({
                  ok: true,
                  json: jest.fn().mockResolvedValue(mockData)
                });
                result = await instance.get(mockPath);
              });
    
              it("should return data", () => {
                expect(result).toEqual(mockData);
              });
    
              it("should request the correct URL", () => {
                expect(global.fetch).toHaveBeenCalledWith(
                  "http://localhost/undefined/pa/th",
                  {
                    method: "GET"
                  }
                );
              });
            });
          });
        });
      });
    });
    
    

    查看full coverage example here

    【讨论】:

    • 这回答了原始问题,但我不能很好地扩展。 GenericService 说它是抽象的,但实际上并没有指定用于实现类的 API。如果GenericSerivice 有十几个抽象属性和方法怎么办?现在你的 DummyService 必须提供十几个存根实现。
    猜你喜欢
    • 2018-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-02
    • 2012-04-12
    • 1970-01-01
    • 2011-02-25
    • 2014-06-20
    相关资源
    最近更新 更多