链式函数调用的 Jest 单元测试

Jest Unit Test for chained function calls

我为此苦苦挣扎了一段时间。单元测试的新手..我正在尝试模拟 -

的单元测试用例
fetchFooter() {
    client.items().type('footer_link')
            .depthParameter(10)
            .toObservable()
            .subscribe((response) => {
                this.setState({
                    resFooter: response.items,
                    resFooterLinked: response.linkedItems,
                });
            });
}

客户在哪里

import { DeliveryClient } from '@kentico/kontent-delivery';

const client = new DeliveryClient({
  projectId: <projectKey>,
  enableAdvancedLogging: false,
});

这是我到目前为止写的,但似乎没有用。

const sample = {
  items: {},
  linkedItems: {}
};//this is my response object

describe("testing client", () => {
  const mockClient = {
    items: jest.fn().mockReturnThis(),
    type: jest.fn().mockReturnThis(),
    depthParameter: jest.fn().mockReturnThis(),
    toObservable: jest.fn().mockReturnThis(),
    subscribe: jest.fn().mockReturnThis(),
  };

  const mockProps = {
    client: mockClient,
  };
  const component = mount(
    <Footer mockProps={mockProps} resFooter={true} resFooterLinked={true} />
  );

  describe("Component", () => {
    describe("#componentDidMount", () => {
      it("should mount the component and set state correctly", () => {
        const mockedResponse = sample;
        mockClient.subscribe.mockImplementationOnce((handler) => handler(sample));
        // tslint:disable-next-line: no-string-literal
        component["setState"] = jest.fn();
        component.instance().fetchFooter();
        expect(
          mockClient.items().type().depthParameter().toObservable().subscribe
        ).toBeCalledWith("footer_link");
        // tslint:disable-next-line: no-string-literal
        expect(component["setState"]).toBeCalledWith(sample);
      });
    });
  });
});

我收到错误消息 -

    expect(jest.fn()).toBeCalledWith(...expected)

    Expected: "footer_link"

    Number of calls: 0

也许我在这里缺少一些基础知识。我为此寻找了解决方案,但不幸的是没有找到适合我的解决方案。 有人能帮忙吗?提前致谢

the reference 所述,mockReturnThis 是以下的快捷方式:

jest.fn(function () {
  return this;
});

它只使函数可链接,不会将参数传递给链中的下一个函数。 subscribe 不应使用 footer_link 调用,它是使用此参数调用的 type

没有必要让 mocked subscribe 调用处理程序,这不能保证 setState 已在其中调用。此外,setState 不是用 sample 而是另一个对象调用的。

在测试中没有必要调用expect(mockClient.items()...)链,这只会增加调用次数。调用断言不允许确定调用方法的顺序,这可以手动确保。

由于模拟客户端对象应该可以在 config 模块模拟中访问,变量需要提升到模块范围,这允许在组件模块中模拟 client

链条可以像这样进行全面测试:

// module scope
jest.mock('../../config', () => ({
  __esModule: true,
  default: mockClient
});

const mockClient = {
  items: jest.fn(),
  type: jest.fn(),
  ...
};
...

// describe scope
let clientCalls;
beforeEach(() => {
  clientCalls = [];

  mockClient.items.mockImplementation(function () { clientCalls.push(1); return this });
  mockClient.type.mockImplementation(function () { clientCalls.push(2); return this });
  ...
});
...

// test scope
component.instance().fetchFooter();

expect(clientCalls).toEqual([1,2,3,4,5]);
expect(mockClient.items).toBeCalledWith();
expect(mockClient.type).toBeCalledWith("footer_link");
...
expect(mockClient.subscribe).toBeCalledWith(expect.any(Function));

let [handler] = mockClient.subscribe.mock.calls[0];
expect(component["setState"]).not.toBeCalled();
handler();
expect(component["setState"]).toBeCalledWith({ resFooter:..., resFooterLinked:...});