Maison >interface Web >js tutoriel >Récapitulatif de la plaisanterie : simulez en toute sécurité les propriétés et les méthodes des objets globaux

Récapitulatif de la plaisanterie : simulez en toute sécurité les propriétés et les méthodes des objets globaux

WBOY
WBOYoriginal
2024-07-19 15:10:32338parcourir

Jest Recap: Safely Mock Properties and Methods of Global Objects

TL;DR :

  • Vous voulez éviter que les propriétés/méthodes remplacées/moquées n'affectent d'autres tests.
  • Pour les objets locaux (créés et détenus par ce test), vous pouvez (et devez) utiliser
    • localObject.theAnswer = 42 et
    • localObject.calcTheAnswer = jest.fn(() => 42).
  • Pour les objets globaux, vous devez utiliser
    • jest.replaceProperty(globalObject, "theAnswer", 42) et
    • jest.spyOn(globalObject, "calcTheAnswer").mockReturnValue(42).
  • Assurez-vous que jest.restoreAllMocks() est appelé dans un hook afterEach().

Quoi?

Dans un monde parfait base de code il n'est pas nécessaire de manipuler des objets globaux, mais le monde bases de code sont désordonnées - et donc est en train de tester.

Ce que vous voulez éviter à tout prix, c'est qu'un test affecte l'autre. Les tests doivent être significatifs quel que soit leur ordre ou si certains tests sont ignorés.

Propriétés moqueuses

Une approche naïve des valeurs fictives consiste simplement à définir les propriétés sur la valeur dont vous avez besoin dans votre test.
C'est très bien tant que vous modifiez les valeurs des objets locaux appartenant (créés par) ce test spécifique :

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

Si vous faites cela pour des objets globaux, cela devient compliqué :

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

C'est pour cela que jest.replaceProperty() a été conçu :

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

Méthodes moqueuses

Les méthodes peuvent être moquées de la même manière que les propriétés.

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();
    });
});

Si vous utilisez myObject.someFunction = jest.fn() sur des objets globaux, vos tests peuvent dépendre les uns des autres et perdre leur sens :

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

Comment devrions-nous nous moquer des méthodes dans les objets globaux ? C'est à cela que sert 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();
    });
});

Vous devez nettoyer

Si vous voulez être sûr que tous les tests trouvent le système dans le même état (frais, propre), vous devez restaurer l'état des simulations après chaque test.

La solution la plus simple consiste à définir la propriété de configuration restaurerMocks.

L'option la plus simple consiste à appeler jest.restoreAllMocks() dans afterEach()

Comment se moquer de quelque chose pour tous les tests

Parfois, vous souhaitez vous moquer de choses pour tous les tests d'un fichier. Si vous utilisez jest.spyOn() et jest.replaceProperty() au niveau supérieur ou dans un bloc décrire(), tous les Mocks seront réinitialisés après l'exécution du premier test.

Au niveau supérieur, vous pouvez remplacer en toute sécurité les propriétés et les méthodes, sans jest.spyOn() et jest.replaceProperty().

Si vous souhaitez vous moquer d'éléments uniquement pour un bloc décrire(), vous devez effectuer ces appels dans un hook beforeEach().

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:Carte en JSArticle suivant:Carte en JS