Override Object Property for unit testing purposes

生来就可爱ヽ(ⅴ<●) 提交于 2020-08-10 22:54:17

问题


I am using Jest to perform unit tests on a Node.js app, where the code source is written in TypeScript and then compiled into JavaScript.

In one of the classes that I wish to test, an external module is imported and a method from this module is used. I want to mock the calls to this method, in order to test only my code.

However, when I run the test, I get the following error:

TypeError: Cannot redefine property: methodName

The problem is that this method has the following Object Properties:

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

The configurable: false is what makes it a big problem. I cannot redefine the properties before my mock call to make it writable.

Here is what the relevant code looks like:

Tested Class

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

Unit Test

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

What I tried so far

  1. I added the following line in my test:

    Object.defineProperty(class['module'], 'methodName', {writable: true});

  2. I defined my mock call as following:

    jest.spyOn(class['module'], 'methodName').mockReturnValue(Promise.resolve());

  3. I defined my mock call as following:

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

  4. I tried to override the property that I'm calling, as following:

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

For this one I get the error TypeError: Cannot assign to read only property externalMethod of object class, which makes sense since readable is set to false.

But everything seems blocked from the attribute configurable. I'm sure there is something that can be done because I am probably not the only one who wants to perform unit tests on a class that imports an external module, as secure as it is.

So my question is: what would be a clean and working way of mocking the external method? And if it is strictly impossible, what would be a way of testing my class without calling that external method?

Thanks in advance!


回答1:


This is a bit of a hack, but until I have a cleaner solution, the following has been an acceptable stop-gap:

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


来源:https://stackoverflow.com/questions/57755086/override-object-property-for-unit-testing-purposes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!