如何在Jest中使用JavaScript模拟服务?

时间:2020-01-31 17:30:21

标签: javascript unit-testing jestjs

我的代码如下

const { MyClient } = require('some-service')

const invokeMe = async (input1, input2) => {
  const client = new MyClient({
    name: 'my-name'
  })

  return await client.invoke({
    input1,
    input2
  }).catch((err) => {
    throw err
  })
}

这就是我所拥有的,如何正确模拟该服务并监视其调用内容?

const { MyClient } = require('some-service')

describe('test my client', () => {
  it('invoke my client', () => {
    const response = {
      data: []
    }
    expect(invokeMe('abc', '123')).resolves.toEqual(response)
    expect(MyClient).toBeCalledWith({
      input1: 'abc',
      input2: '123'
    })
  })
})

编辑:为什么下面的代码仍然调用原始函数?

it('invoke my client', () => {
  const mockInvoke = jest.fn().mockImplementation(() => Promise.resolve({
    data: []
  }))
  const mockMyClient = () => {
    return { invoke: mockInvoke }
  }
  const mockSomeService = {
    MyClient: mockMyClient
  }
  jest.doMock('some-service', () => mockSomeService
  ...
})

1 个答案:

答案 0 :(得分:0)

您可以使用jest.mock(moduleName, factory, options)模拟导入的服务

例如

index.js

const { MyClient } = require('./some-service');

const invokeMe = async (input1, input2) => {
  const client = new MyClient({
    name: 'my-name',
  });

  return await client
    .invoke({
      input1,
      input2,
    })
    .catch((err) => {
      throw err;
    });
};

module.exports = invokeMe;

some-service.js

class MyClient {
  async invoke(input1, input2) {
    return 'real response';
  }
}

module.exports = { MyClient };

index.test.js

const invokeMe = require('./');
const { MyClient } = require('./some-service');

jest.mock('./some-service', () => {
  const mMyClient = { invoke: jest.fn() };
  return { MyClient: jest.fn(() => mMyClient) };
});

describe('60008679', () => {
  it('should invoke', async () => {
    const client = new MyClient();
    client.invoke.mockResolvedValueOnce('fake response');
    const actual = await invokeMe('a', 'b');
    expect(actual).toBe('fake response');
    expect(MyClient).toBeCalledWith({ name: 'my-name' });
    expect(client.invoke).toBeCalledWith({ input1: 'a', input2: 'b' });
  });

  it('should handle error', async () => {
    const client = new MyClient();
    const mError = new Error('some error');
    client.invoke.mockRejectedValueOnce(mError);
    await expect(invokeMe('a', 'b')).rejects.toThrowError(mError);
    expect(MyClient).toBeCalledWith({ name: 'my-name' });
    expect(client.invoke).toBeCalledWith({ input1: 'a', input2: 'b' });
  });
});

单元测试结果覆盖率100%:

 PASS  src/stackoverflow/60008679/index.test.js (11.029s)
  60008679
    ✓ should invoke (8ms)
    ✓ should handle error (4ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |      100 |      100 |      100 |      100 |                   |
 index.js |      100 |      100 |      100 |      100 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        12.314s

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/60008679