Using Jest + TypeScript, how do I mock a static method used in another static method of a class being tested?

huangapple go评论63阅读模式
英文:

Using Jest + TypeScript, how do I mock a static method used in another static method of a class being tested?

问题

我有两个类 ClassAClassB,它们只包含静态方法。ClassA 中的一个方法叫做 staticMethodA(),它调用了 ClassB 中的一个静态方法,叫做 staticMethodB

import { ClassB } from './classB';

export class ClassA {
    public static async staticMethodA() {
        return await ClassB.staticMethodB();
    }
}

在为 staticMethodA() 编写单元测试时,我希望模拟 staticMethodB() 以更好地隔离 staticMethodA()。根据现有的在线指南,我创建了以下测试:

describe('staticMethodA', () => {
    let classA;

    const mockStaticMethodB = jest.fn().mockResolvedValue({}); // 返回一个虚拟对象

    beforeAll(() => {

        // 模拟 ClassB
        jest.mock('../src/classB', () => () => ({

            ClassB: { 
                staticMethodB: mockStaticMethodB
            }

        })}};

        // 在模拟 ClassB 后导入 ClassA,以便它引用模拟
        classA = require('../src/classA');
    }

    it('应该调用 mockStaticMethodB', async () => {

        // 从 require 返回的对象是包含 ClassA 的对象
        const actual = await classA.ClassA.staticMethodA();

        expect(actual).toBe({}); // 虚拟对象
    }

    afterAll(() => {
        jest.unmock('../src/classB');
    });
}

staticMethodA 调用 staticMethodB 时,我收到一个错误,说 ClassB 未定义。当我在 return await ClassB.staticMethodB(); 上设置断点时,我看到有一个名为 classB_1 的变量可用,但没有 ClassB

我尝试了一些在以下资源中找到的模拟构建策略,但仍然导致 ClassB 未定义:

英文:

I have two classes ClassA and ClassB that contain only static methods. One of the methods in ClassA, called staticMethodA(), calls a static method from ClassB, called staticMethodB.

import { ClassB } from './classB'

export class ClassA {
    public static async staticMethodA() {
        return await ClassB.staticMethodB();
    }
}

While working on a unit test for staticMethodA(), I wanted to mock staticMethodB() to better isolate staticMethodA(). Following existing guidance online, I created the following test:

    describe('staticMethodA', () => {
        let classA;

        const mockStaticMethodB = jest.fn().mockResolvedValue({}); //return dummy object

        beforeAll(() => {

            // Mocking ClassB
            jest.mock('../src/classB', () => () => ({

                ClassB: { 
                    staticMethodB: mockStaticMethodB
                }

            })}};

            // Importing ClassA after mocking ClassB so it references the mock
            classA = require('../src/classA');
        }

        it('should call mockStaticMethodB', async () => {

            //The object returned from require is an object containing ClassA
            const actual = await classA.ClassA.staticMethodA();

            expect(actual).toBe({}); // dummyObject
        }

        afterAll(() => {
            jest.unmock('../src/classB');
        });
    }

I get an error when staticMethodA calls staticMethodB that says that ClassB is undefined. When I set a breakpoint on return await ClassB.staticMethodB();, I see there's a variable called classB_1 available but not ClassB.

I've tried some of the mock construction strategies found in the following resources, but all still resulted in ClassB being undefined:

答案1

得分: 1

以下是代码的翻译部分:

// classa.test.ts
import { ClassA } from '../classA';
// 直接导入了 ClassB
// 这将是被模拟的版本
import { ClassB } from '../classB';

// 模拟应该提升到模块的顶部
jest.mock('../classB', () => {
    return {
        ClassB: {
            staticMethodB: jest.fn(),
        },
    };
});

describe('classA', () => {
    it('应该调用 mockStaticMethodB', async () => {
        // 由于 ClassB 是一个模拟,我们可以为这个测试用例提供返回值
        (ClassB.staticMethodB as jest.Mock).mockReturnValueOnce(42);
        const actual = await ClassA.staticMethodA();

        // 请注意,在模拟和这里,我们都使用 42 进行比较,因为它适用于 `expect().toBe()`
        // 如果我们想要比较对象,我们将使用 `expect().toEqual()` 代替
        expect(actual).toBe(42);
    });
});
英文:

There are a few things that would need changing in this case. I've tested this locally and it works.

// classa.test.ts
import {ClassA} from '../classA';
// we are importing ClassB directly
// this will be the mocked version
import {ClassB} from '../classB';

// mock should be hoisted to the top of the module
jest.mock('../classB', () => {
    return {
        ClassB: {
            staticMethodB: jest.fn(),
        },
    };
});

describe('classA', () => {
    it('should call mockStaticMethodB', async () => {
        // since ClassB is a mock we can provide the return value for this test case only
        (ClassB.staticMethodB as jest.Mock).mockReturnValueOnce(42);
        const actual = await ClassA.staticMethodA();

        // note that in both mock and here we are using 42 for comparison as it works with `expect().toBe()`
        // if we wanted to compare objects we would use `expect().toEqual()` instead
        expect(actual).toBe(42);
    });
});

huangapple
  • 本文由 发表于 2023年2月24日 03:24:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75549444.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定