首页 > web前端 > js教程 > 笑话回顾:安全模拟全局对象的属性和方法

笑话回顾:安全模拟全局对象的属性和方法

WBOY
发布: 2024-07-19 15:10:32
原创
364 人浏览过

Jest Recap: Safely Mock Properties and Methods of Global Objects

长话短说:

  • 您希望避免覆盖/模拟的属性/方法影响其他测试。
  • 对于本地对象(由该测试创建并拥有),您可以(并且应该)使用
    • localObject.theAnswer = 42 和
    • localObject.calcTheAnswer = jest.fn(() => 42).
  • 对于全局对象,您应该使用
    • jest.replaceProperty(globalObject, "theAnswer", 42) 和
    • jest.spyOn(globalObject, "calcTheAnswer").mockReturnValue(42).
  • 确保在 afterEach() 挂钩中调用 jest.restoreAllMocks()。

什么?

在一个完美的世界 代码库中,不需要操作全局对象,但是世界 代码库很混乱 - 所以正在测试。

您要不惜一切代价避免一个测试影响另一个测试。无论测试的顺序如何,或者是否跳过某些测试,测试都应该有意义。

模拟属性

模拟值的一种简单方法是将属性设置为测试中所需的任何值。
只要您更改此特定测试拥有(创建)的本地对象中的值就可以了:

describe("override properties of local objects", () => {
    it("works and is harmless", () => {
        const myArray = [1];
        myArray.length = 0;
        expect(myArray).toHaveLength(0);
    });
    it("does not affect the next test", () => {
        const myArray = [1];
        expect(myArray).toHaveLength(1);
    });
});
登录后复制

如果你对全局对象这样做,它会变得混乱:

describe("don't override properties of global objects", () => {
    it("works before the property is overridden", () => {
        expect(window.innerWidth).toBeGreaterThan(0);
    });
    it("works, but is evil", () => {
        window.innerWidth = 0;
        expect(window.innerWidth).toBe(0);
    });
    it("fails in the test after the property was overridden", () => {
        expect(() => {
            expect(window.innerWidth).toBeGreaterThan(0); // <-- ERROR: expect(received).toBeGreaterThan(expected)
        }).toThrow(Error);
    });
});
登录后复制

这就是 jest.replaceProperty() 的用途:

describe("use jest.replaceProperty() to override properties of global objects", () => {
    afterEach(() => {
        jest.restoreAllMocks();
    });
    it("works before the property is overridden", () => {
        expect(window.innerWidth).toBeGreaterThan(0);
    });
    it("works and is harmless", () => {
        jest.replaceProperty(window, "innerWidth", 0);
        expect(window.innerWidth).toBe(0);
    });
    it("does not affect the next test", () => {
        expect(window.innerWidth).toBeGreaterThan(0);
    });
});
登录后复制

模拟方法

方法可以像属性一样被模拟。

describe("override methods of local objects using jest.fn()", () => {
    it("works and is harmless", () => {
        const mySet = new Set([1]);
        mySet.has = jest.fn().mockReturnValue(false);
        expect(mySet.has(1)).toBeFalsy();
    });
    it("does not affect the next test", () => {
        const mySet = new Set([1]);
        expect(mySet.has(1)).toBeTruthy();
    });
});
登录后复制

如果您在全局对象上使用 myObject.someFunction = jest.fn(),您的测试可能会相互依赖并失去其意义:

describe("don't override methods of global objects using jest.fn()", () => {
    it("works before the method is overridden", () => {
        expect(document.getElementById("foo")).toBeNull();
    });
    it("works, but is evil", () => {
        const el = document.createElement("div");
        document.getElementById = jest.fn().mockReturnValue(el);

        expect(document.getElementById("foo")).toBe(el);
    });
    it("fails in the test after the property was overridden", () => {
        expect(() => {
            expect(document.getElementById("foo")).toBeNull(); // <-- ERROR: expect(received).toBeNull()
        }).toThrow(Error);
    });
});
登录后复制

我们应该如何模拟全局对象中的方法?这就是 jest.spyOn() 的优点:

describe("use jest.spyOn() to override methods of global objects", () => {
    afterEach(() => {
        jest.restoreAllMocks();
    });
    it("works before the method is overridden", () => {
        expect(document.getElementById("foo")).toBeNull();
    });
    it("works and is harmless", () => {
        const el = document.createElement("div");
        jest.spyOn(document, "getElementById").mockReturnValue(el);

        expect(document.getElementById("foo")).toBe(el);
    });
    it("does not affect the next test", () => {
        expect(document.getElementById("foo")).toBeNull();
    });
});
登录后复制

你必须清理

如果您想确保所有测试都发现系统处于相同(新鲜、干净)状态,则需要在每次测试后恢复模拟的状态。

最简单的解决方案是设置restoreMocks配置属性。

最直接的选择是在 afterEach() 中调用 jest.restoreAllMocks()

如何为所有测试模拟某些内容

有时您想模拟文件中所有测试的内容。如果您在顶层或在describe()块中使用jest.spyOn()和jest.replaceProperty(),则在执行第一个测试后所有Mock将被重置。

在顶层,您可以安全地重写属性和方法,无需 jest.spyOn() 和 jest.replaceProperty()。

如果您只想为describe() 块模拟事物,则需要在beforeEach() 挂钩中进行这些调用。

以上是笑话回顾:安全模拟全局对象的属性和方法的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板