【问题标题】:Jest Unit Test for chained function calls用于链式函数调用的 Jest 单元测试
【发布时间】:2020-10-01 00:33:57
【问题描述】:

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

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

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

【问题讨论】:

    标签: reactjs ecmascript-6 jestjs enzyme kentico


    【解决方案1】:

    正如the reference 所说,mockReturnThis 是:

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

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

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

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

    由于模拟的客户端对象应该可以在 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:...});
    

    【讨论】:

    • clientCalls 给出了一个空白数组。似乎 mockClient 变量没有被分配给对象。所以我尝试在顶部将 mockClient 定义为这个对象,但仍然给我错误 - Number of calls: 0.. 我错过了什么吗?
    • 这取决于你如何模拟它,这在问题中没有显示。如果你不这样做,mockClient 将不会被神奇地使用而不是 client。请显示client 在组件中的确切显示方式。如果已导入,则应在模块级别进行模拟。
    • 哦.. 是的,在组件(.js)中,我已经从其他文件中导入了客户端,像这样 - import client from '../../config';... 所以我需要对测试(test.js)做一些更改为此?
    • 是的,你肯定会。还要确保在每次测试之前重置 Jest 间谍,请参阅 jestjs.io/docs/en/configuration#restoremocks-boolean
    • 这有帮助.. 非常感谢!
    猜你喜欢
    • 2018-01-21
    • 2019-05-16
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 2021-06-16
    • 1970-01-01
    相关资源
    最近更新 更多