在 NodeJS 中使用 Jest 对类进行部分模拟

问题描述 投票:0回答:1

我有一个函数

extractPayloadDates
,它接受对话流
Agent
的实例并从中获取和解析数据。我只想模拟
getParameter
的单个方法
Agent
,因为测试函数中没有使用更多方法。我在网上找到了这个代码,但它不起作用

import { Agent } from '../../src/dialogflow/Agent';
import { extractPayloadDates } from '../../src/intents/extractPayloadDates';

describe('extractPayloadDates', () => {
  it('tests extracting string', () => {
    const AgentMock = jest.fn<Agent, []>(() => ({
      getParameter: () => {
        return 'some date';
      }
    }));
    const agent = new AgentMock();

    expect(extractPayloadDates(agent)).toEqual('some date');
  });
});

此代码产生以下错误:

输入 '{ getParameter: () => string; }' 缺少类型“Agent”中的以下属性:payload、webhookClient、chatter、getOriginalRequest 和 13 more.ts(2740) index.d.ts(124, 53):预期类型来自此签名的返回类型。

我也尝试使用

jest.spyOn
,但问题是,我无法创建代理实例,因为它需要许多其他对象。


使用更多代码编辑 3.9.2019

代理.ts

export class Agent {
  private payload: DialogFlowPayload[] = [];

  constructor(readonly webhookClient: WebhookClient, private readonly chatter: Chatter) {}
...
}

WebhookClientChatter 在其构造函数中也有更多依赖项...

extractPayloads.spec.ts

import { Agent } from '../../src/dialogflow/Agent';
import { extractPayloadDates } from '../../src/intents/extractPayloadDates';

describe('extractPayloadDates', () => {
  it('tests extracting string', () => {
    const webhookMock = jest.fn();
    const chatter = jest.fn();
    const agent = new Agent(webhookMock, chatter);

    expect(extractPayloadDates(agent)).toEqual('some date');
  });
});

这会产生另一个错误:

“Mock”类型的参数不可分配给“Chatter”类型的参数。 “Mock”类型中缺少属性“getMessage”,但“Chatter”类型中需要属性“getMessage”

我真的还必须创建 WebhookClient 及其所有依赖项并对 Chatter 执行相同的操作吗?如果这样做,我必须创建多个类的实例只是为了模拟 Agent 中的 1 个方法,然后该方法将不会使用任何依赖项。

node.js unit-testing mocking jestjs
1个回答
3
投票

来自 jest 的文档

如果想覆盖原来的函数,可以使用 jest.spyOn(object, methodName).mockImplementation(() => customImplementation) 或 object[methodName] = jest.fn(() => customImplementation);

jest.spyOn
内部调用
jest.fn
。所以你只能像这样模拟
getParameter
代理方法:

extractPayloadDates.ts

function extractPayloadDates(agent) {
  return agent.getParameter();
}

export { extractPayloadDates };

Agent.ts

interface DialogFlowPayload {}
interface WebhookClient {}
interface Chatter {
  getMessage(): any;
}
class Agent {
  private payload: DialogFlowPayload[] = [];

  constructor(readonly webhookClient: WebhookClient, private readonly chatter: Chatter) {}

  public getParameter() {
    return 'real data';
  }

  public otherMethod() {
    return 'other real data';
  }
}

export { Agent, Chatter };

单元测试,仅mock

getParameter
agent
方法,保留
otherMethod

原来的实现
import { extractPayloadDates } from './extractPayloadDates';
import { Agent, Chatter } from './Agent';

const webhookMock = jest.fn();
const chatter: jest.Mocked<Chatter> = {
  getMessage: jest.fn()
};

const agent = new Agent(webhookMock, chatter);

describe('extractPayloadDates', () => {
  it('should only mock getParameter method of agent', () => {
    agent.getParameter = jest.fn().mockReturnValueOnce('mocked data');
    const actualValue = extractPayloadDates(agent);
    expect(actualValue).toEqual('mocked data');
    expect(agent.otherMethod()).toBe('other real data');
  });
});

 PASS  src/stackoverflow/57428542/extractPayloadDates.spec.ts
  extractPayloadDates
    ✓ should only mock getParameter method of agent (7ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.484s, estimated 3s
© www.soinside.com 2019 - 2024. All rights reserved.