在Jest中,如何仅在特定测试中模拟外部模块?

时间:2019-06-04 15:03:34

标签: typescript unit-testing mocking jestjs

我正在将Jest与TypeScript结合使用(使用ts-jest)。这是我使用dotenv库的测试主题:

import * as dotenv from 'dotenv';

export class TestSubject {
  public function test() {
    console.log(dotenv); // Here I debug if I'm using a mock or not
  }
}

我只想为特定测试模拟dotenv库,但是我被困住了。

这是我的测试套件:

import { TestSubject } from './test-subject';
import * as dotenv from 'dotenv';

jest.mock('dotenv'); // place it here, otherwise it doesn't work

describe('Suite 1', () => {
  it('test 1', () => {
    // I want to use the mock here... and it works
    const subject = new TestSubject();
    subject.test(); // shows that I'm using the mock
  });

  it('test 2', () => {
    // I don't want the mock here
    jest.dontMock('dotenv'); // doesn't work
    jest.unmock('dotenv');   // doesn't work

    const subject = new TestSubject();
    subject.test(); // shows that I'm still using the mock!!!
  });
});

如您所见,调用jest.mock('dotenv')应该放在describe的外部,否则它将不起作用。

我试图在 test 2 中不使用该模拟,但是它不起作用:console.log显示我正在使用该模拟。

2 个答案:

答案 0 :(得分:1)

@ slideshowp2解决方案的改进。

对于jest.domock,您需要在模块(like here)之后调用require,但是require的结果具有any类型,我们会丢失类型安全。因此您可以使用typescript's dynamic imports

完整代码示例:

import * as summer from './exampleModule';

describe('mock vs no-mock', () => {
    beforeEach(() => {
        jest.resetModules();
    });

    it('NO-MOCKED', async () => {
        console.log(summer.sum(1, 1));
        expect(summer.sum(1, 1)).toBe(2);
    });
    it('MOCKED', async () => {
        jest.doMock('./exampleModule');
        const summer = await import('./exampleModule');

        const mockedSummer = mocked(summer, true);
        mockedSummer.sum.mockImplementation((a, b) => a + b + 1);
        console.log(summer.sum(1, 1));
        expect(summer.sum(1, 1)).toBe(3);
    });
    it('NO-MOCKED', async () => {
        console.log(summer.sum(1, 1));
        expect(summer.sum(1, 1)).toBe(2);
    });
});

答案 1 :(得分:0)

这是解决方案:

index.ts,将对文件进行测试:

import * as dotenv from 'dotenv';

export class TestSubject {
  public test() {
    console.log(dotenv);
  }
}

单元测试:

describe('TestSubject', () => {
  beforeEach(() => {
    jest.resetModules();
  });
  it('should mock dotenv', () => {
    jest.doMock('dotenv');
    const dotenv = require('dotenv');
    const { TestSubject } = require('./');
    const subject = new TestSubject();
    subject.test();
    expect(jest.isMockFunction(dotenv.config)).toBeTruthy();
  });

  it('should not mock dotenv', () => {
    jest.unmock('dotenv');
    const dotenv = require('dotenv');
    const { TestSubject } = require('./');
    const subject = new TestSubject();
    subject.test();
    expect(jest.isMockFunction(dotenv.config)).toBeFalsy();
  });
});

单元测试结果:

 PASS  src/stackoverflow/56446543/index.spec.ts
  TestSubject
    ✓ should mock dotenv (2111ms)
    ✓ should not mock dotenv (2ms)

  console.log src/stackoverflow/56446543/index.ts:5
    { config: 
       { [Function: config]
         _isMockFunction: true,
         getMockImplementation: [Function],
         mock: [Getter/Setter],
         mockClear: [Function],
         mockReset: [Function],
         mockRestore: [Function],
         mockReturnValueOnce: [Function],
         mockResolvedValueOnce: [Function],
         mockRejectedValueOnce: [Function],
         mockReturnValue: [Function],
         mockResolvedValue: [Function],
         mockRejectedValue: [Function],
         mockImplementationOnce: [Function],
         mockImplementation: [Function],
         mockReturnThis: [Function],
         mockName: [Function],
         getMockName: [Function] },
      parse: 
       { [Function: parse]
         _isMockFunction: true,
         getMockImplementation: [Function],
         mock: [Getter/Setter],
         mockClear: [Function],
         mockReset: [Function],
         mockRestore: [Function],
         mockReturnValueOnce: [Function],
         mockResolvedValueOnce: [Function],
         mockRejectedValueOnce: [Function],
         mockReturnValue: [Function],
         mockResolvedValue: [Function],
         mockRejectedValue: [Function],
         mockImplementationOnce: [Function],
         mockImplementation: [Function],
         mockReturnThis: [Function],
         mockName: [Function],
         getMockName: [Function] },
      default: 
       { config: 
          { [Function: config]
            _isMockFunction: true,
            getMockImplementation: [Function],
            mock: [Getter/Setter],
            mockClear: [Function],
            mockReset: [Function],
            mockRestore: [Function],
            mockReturnValueOnce: [Function],
            mockResolvedValueOnce: [Function],
            mockRejectedValueOnce: [Function],
            mockReturnValue: [Function],
            mockResolvedValue: [Function],
            mockRejectedValue: [Function],
            mockImplementationOnce: [Function],
            mockImplementation: [Function],
            mockReturnThis: [Function],
            mockName: [Function],
            getMockName: [Function] },
         parse: 
          { [Function: parse]
            _isMockFunction: true,
            getMockImplementation: [Function],
            mock: [Getter/Setter],
            mockClear: [Function],
            mockReset: [Function],
            mockRestore: [Function],
            mockReturnValueOnce: [Function],
            mockResolvedValueOnce: [Function],
            mockRejectedValueOnce: [Function],
            mockReturnValue: [Function],
            mockResolvedValue: [Function],
            mockRejectedValue: [Function],
            mockImplementationOnce: [Function],
            mockImplementation: [Function],
            mockReturnThis: [Function],
            mockName: [Function],
            getMockName: [Function] } } }

  console.log src/stackoverflow/56446543/index.ts:5
    { config: [Function: config],
      parse: [Function: parse],
      default: { config: [Function: config], parse: [Function: parse] } }

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        3.394s, estimated 4s

如您所见,dotenv模块在​​第一个测试用例中被模拟,而在第二个测试用例中没有模拟。

您可以在此处找到完整的演示:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/56446543