简体   繁体   English

如何使用 Jest 仅为特定测试模拟模块的功能

[英]How to mock a module's function only for a specific test with Jest

I need to mock the function of a dependency but only for a specific test case.我需要模拟依赖项的功能,但仅适用于特定的测试用例。 In my other tests, I want to leave the module as is.在我的其他测试中,我想保持模块不变。 I am also mocking other modules.我也在嘲笑其他模块。 Those need to stay mocked.那些需要保持嘲笑。

I tried multiple approaches as many variants of this question have been asked, but due to my need to use the original module when not mocked, none of the other solutions seem to work...我尝试了多种方法,因为已经提出了这个问题的许多变体,但是由于我需要在未模拟时使用原始模块,因此其他解决方案似乎都不起作用......

Here's an example of what I would need这是我需要的示例

// app.ts
import * as moduleA from 'moduleA';

// ...

app.post('/signup', async (req, res) => {
   // ...
   const hashed = await moduleA.hash(req.body.password);
   // ...
});

export default app;


// app.test.ts

// some mocks
jest.mock('./database', () => ({ ... }));
// ...

import * as request from 'supertest';
import app from './app';

// ...

describe('A', () => {
    test('Those should work', async () => {
        const response = await request(app).post('/signup').send({ password: 'pw' });
        expect(response.status).toBe(200);
        // ...
    });
    // many other tests
    
    test('I need to force hash to crash here', async () => {
        // mock moduleA.hash only for this test
        const response = request(app).post('/signup').send({ password: 'pw' });
        expect(response.status).toBe(500);
    });

    test('moduleA.hash should be back to its default function', async () => {
        // request(app) and moduleA.hash will work properly, not mocked
        // ./database stays mocked
    });
});

You can use jest.spyOn() to mock the hash method of moduleA , and use .mockRestore() to restore the hash method to original implementation.您可以使用jest.spyOn()嘲笑hash的方法moduleA ,并使用.mockRestore()恢复hash方法最初实现。

Here is the solution:这是解决方案:

app.ts : app.ts

import express from 'express';
import bodyParser from 'body-parser';

import * as moduleA from './moduleA';
const app = express();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.post('/signup', async (req, res) => {
  try {
    const hashed = await moduleA.hash(req.body.password);
    console.log(hashed);
    res.sendStatus(200);
  } catch (error) {
    res.sendStatus(500);
  }
});

export default app;

moduleA.ts : moduleA.ts

export const hash = async (data: string) => {
  return 'real hashed value';
};

app.spec.ts : app.spec.ts

import app from './app';
import request from 'supertest';
import * as moduleA from './moduleA';

describe('app', () => {
  test('Those should work', async () => {
    const response = await request(app)
      .post('/signup')
      .send({ password: 'pw' });
    expect(response.status).toBe(200);
  });

  test('I need to force hash to crash here', async () => {
    const mockedError = new Error('hash error');
    const hashSpy = jest.spyOn(moduleA, 'hash').mockRejectedValueOnce(mockedError);
    const response = await request(app)
      .post('/signup')
      .send({ password: 'pw' });
    expect(response.status).toBe(500);
    expect(moduleA.hash).toBeCalledWith('pw');
    hashSpy.mockRestore();
  });

  test('moduleA.hash should be back to its default function', async () => {
    const logSpy = jest.spyOn(console, 'log');
    const response = await request(app)
      .post('/signup')
      .send({ password: 'pw' });
    expect(response.status).toBe(200);
    expect(logSpy).toBeCalledWith('real hashed value');
  });
});

Unit test result with 100% coverage: 100% 覆盖率的单元测试结果:

PASS  src/stackoverflow/47540126/app.spec.ts
  app
    ✓ Those should work (72ms)
    ✓ I need to force hash to crash here (10ms)
    ✓ moduleA.hash should be back to its default function (14ms)

  console.log src/stackoverflow/47540126/app.ts:3569
    real hashed value

  console.log node_modules/jest-mock/build/index.js:860
    real hashed value

------------|----------|----------|----------|----------|-------------------|
File        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files   |      100 |      100 |      100 |      100 |                   |
 app.ts     |      100 |      100 |      100 |      100 |                   |
 moduleA.ts |      100 |      100 |      100 |      100 |                   |
------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        4.156s, estimated 5s

Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47540126这是完整的演示: https : //github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/47540126

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM