最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - how to mock a constructor being initiated from inside a method with jest - Stack Overflow

programmeradmin0浏览0评论

i have a script that defines 2 classes, and 1 gets instantiated from within the constructor of the other. how can i mock the nested constructor, so i can test the parent constructor?

export default class Foo {
  // i want to test this constructor...
  constructor() {
    new Bar
  }
}

export class Bar {
  // but mock this constructor
  constructor() {}
}

additionally, i am trying to spy on the Bar constructor, to assert that it has been called

i have tried several different approaches, but haven't been able to get the results i am looking for. i am new to the jest mocking library

i have a script that defines 2 classes, and 1 gets instantiated from within the constructor of the other. how can i mock the nested constructor, so i can test the parent constructor?

export default class Foo {
  // i want to test this constructor...
  constructor() {
    new Bar
  }
}

export class Bar {
  // but mock this constructor
  constructor() {}
}

additionally, i am trying to spy on the Bar constructor, to assert that it has been called

i have tried several different approaches, but haven't been able to get the results i am looking for. i am new to the jest mocking library

Share Improve this question edited Oct 27, 2020 at 6:29 Lin Du 103k135 gold badges332 silver badges564 bronze badges asked Oct 27, 2020 at 6:09 brewsterbrewster 4,5027 gold badges48 silver badges72 bronze badges 2
  • Are these classes both in the same module? I read this recently, which suggests that you should separate them into different module files if you want to mock one and not the other. – Patrick Roberts Commented Oct 27, 2020 at 6:11
  • A constructor is the same as a class that it represents. Literally, Bar.prototype.constructor === Bar. So that it's a constructor doesn't offer any opportunities regarding testing. You cannot mock a variable that is used in the same module where it was defined, end of the story. That Foo constructor contains side effect and ignores Bar instance is potentially an antipattern and should be addressed in the first place. If there were this.bar = new Bar you could assert it. – Estus Flask Commented Oct 27, 2020 at 7:58
Add a ment  | 

1 Answer 1

Reset to default 6

Need to make a little modification to the module export statement. Then, we can use jest.spyOn(object, methodName) method to mock implementation for Bar class. Take a look at the code after piling. We create the mocked Bar in the module export object and we use it in the Foo class. It has the same reference as the mocked one.

Remend way:

  1. Dependency Injection
  2. Each file contains ONLY ONE class. So that we can use jest.mock or jest.doMock method to mock the class without modifying the module export statement.

E.g.

index.ts:

export default class Foo {
  constructor() {
    new exports.Bar();
  }
}

class Bar {
  constructor() {
    console.log('real Bar constructor implmentation');
  }
}

exports.Bar = Bar;

index.test.ts:

import * as mod from './';

console.log(mod);

describe('64549093', () => {
  it('should pass', () => {
    const BarConstructorMock = jest.spyOn(mod as any, 'Bar').mockImplementationOnce(() => {
      console.log('fake Bar constructor implmentation');
    });
    new mod.default();
    expect(BarConstructorMock).toBeCalled();
  });
});

unit test result:

 PASS  src/stackoverflow/64549093/index.test.ts (9.905s)
  64549093
    ✓ should pass (5ms)

  console.log src/stackoverflow/64549093/index.test.ts:3
    { default: [Function: Foo], Bar: [Function: Bar] }

  console.log src/stackoverflow/64549093/index.test.ts:8
    fake Bar constructor implmentation

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.751s, estimated 12s

About the configuration of jestjs, TypeScript, see example: https://github./mrdulin/jest-codelab/tree/master/src/stackoverflow/64549093

发布评论

评论列表(0)

  1. 暂无评论