javascript - Åsidosätt objektets egenskap för enhetstestningsändamål


Jag använder Jest för att utföra enhetstester på en Node.js-app, där källkoden är skriven i TypeScript och sedan kompilerad till JavaScript.

I en av de klasser som jag vill testa importeras en extern modul och en metod från denna modul används. Jag vill mocka anropen till denna metod för att endast testa min egen kod.

Men när jag kör testet får jag följande fel:

TypeError: Cannot redefine property: methodName

Problemet är att denna metod har följande objektattribut:

{ value: [Function],
  writable: false,
  enumerable: true,
  configurable: false }

configurable: false är det som gör det till ett stort problem. Jag kan inte definiera om egenskaperna innan mitt mock-anrop för att göra dem skrivbara.

Här är hur den relevanta koden ser ut:

Testad klass

import externalType from 'external-module-name';

export class ClassName {
    public propertyName: externalType;

    public method(param: string): Promise<any> {
        return new Promise((resolve, reject) => {
            this.propertyName.externalMethod(param)
            .then((res) => {
                resolve(res);
            })
            .catch((err) => {
                reject(err);
            });
        });
    }
}

Enhetstest

import { ClassName } from 'path/to/class';

describe('class', () => {
    const class = new ClassName;

    it("Blahblah", (done) => {
        Object.defineProperty(class['propertyName'], 'externalMethod', {writable: true});
        const spy = jest.spyOn(class['propertyName'], 'externalMethod').mockReturnValue(Promise.resolve());
        class.method('string')
        .then((result) => {
            // Various expect()
            done();
        });
    });
});

Vad jag har försökt hittills

  1. Jag lade till följande rad i mitt test:

    Object.defineProperty(class['module'], 'methodName', {writable: true});
  2. Jag definierade mitt mock-anrop på följande sätt:

    jest.spyOn(class['module'], 'methodName').mockReturnValue(Promise.resolve());
  3. Jag definierade mitt mock-anrop på följande sätt:

    class.propertyName.externalMethod=jest.fn().mockImplementation((query) => { return Promise.resolve(); });

  4. Jag försökte skriva över egenskapen som jag anropar, enligt följande:

    class.propertyName=<any> { externalMethod=(param: any) => { return Promise.resolve(); } }

För den här får jag felet TypeError: Cannot assign to read only property externalMethod of object class, vilket är vettigt eftersom readable är satt till false.

Men allt verkar blockerat från attributet configurable. Jag är säker på att det finns något som kan göras eftersom jag förmodligen inte är den enda som vill utföra enhetstester på en klass som importerar ett externt modul, så säkert som det är.

Så min fråga är: vad skulle vara ett rent och fungerande sätt att mocka den externa metoden? Och om det är strikt omöjligt, vad skulle vara ett sätt att testa min klass utan att kalla på den externa metoden?

Tack i förväg!

Svar #1

Jag upptäckte att genom att göra:

jest.mock('path/to/class');

Jag kunde komma runt detta.

Svar #2

Det här är lite av ett hack, men tills jag har en renare lösning har följande varit ett acceptabelt tillfälligt stoppgap:

let override: boolean | undefined;

static before() {
    Object.defineProperty(module, 'readonlyProperty', {
        get() {
            return this.override;
        }
    });
}

@test
public test() {
    this.override = false;
    expect(module.readonlyProperty).to.be.false;
}

---- UPPDATERING ----

Om du använder sinon sandlådor, använd replace-API:et

const sandbox = sinon.createSandbox();
sandbox.replace(module, 'readonlyProperty', false);

Relaterade artiklar