如何使用 jest 和酶测试 API 调用?

Posted

技术标签:

【中文标题】如何使用 jest 和酶测试 API 调用?【英文标题】:How to test API calls in react using jest and enzyme? 【发布时间】:2018-09-28 00:21:45 【问题描述】:

我有一个 React 容器,我正在其中进行 API 调用,并希望能够使用 jest 和酶来测试它,但不确定如何去做。

这是我的代码:

import React from "react";
import Search from "../../components/Search";
import  API_KEY  from "../../../config";

class SearchContainer extends React.Component 
  state = 
    articles: []
  ;

  performSearch = event => 
    fetch(
      `http://content.guardianapis.com/search?q=$event&api-key=$API_KEY`
    )
      .then(response => response.json())
      .then(data => this.setState( articles: data.response.results ));
  ;

  render() 
    return (
      <Search
        performSearch=this.performSearch
        articles=this.state.articles
      />
    );
  


export default SearchContainer;

【问题讨论】:

【参考方案1】:

单元测试的好处在于,它们迫使您编写更好的代码。因此,要正确测试此组件,您应该执行以下操作:

    从组件中提取 performSearch 到一个单独的文件中,例如api.js

    在您的 api.js 文件中模拟 performSearch (jest: mock a module)

    现在您可以测试是否调用了 fetch 函数。

请注意,使用此代码组织,您可以在不调用 API 服务的情况下单独测试 API 调用和 SearchContainer。

【讨论】:

您好,感谢您的回复。我已经按照你说的做了。你能告诉我如何为此编写测试吗?【参考方案2】:

我会通过将performSearch 提取到一个包装fetch 的模块中来解决这个问题。请参阅 this great article 测试不属于您的东西。

之后,如果您将文章状态存储在搜索组件中,您可能不再需要SearchContainer。由于您已经在使用 performSearch 属性的依赖注入,您可以传入一个模拟对象来代替它并使用 jest.fn() 来确保它被调用。

例如:

const fakePerformSearch = jest.fn();
const component = Shallow(<Search performSearch=fakePerformSearch/>);
expect(fakePerformSearch).toHaveBeenCalled();

然后像测试任何 javascript 一样测试新的 fetch 包装器。

【讨论】:

您好,感谢您的回答!我去提取了API,您能检查一下是否可以吗? import API_KEY from "../../config"; const fetchArticles = event =&gt; return fetch( `http://content.guardianapis.com/search?q=$event&amp;api-key=$API_KEY` ).then(response =&gt; response.json()); ; export default fetchArticles;【参考方案3】:

许多其他答案建议使用 Jest 的导入模拟器或模拟函数,但是,这会测试实现而不是行为。

最好是存根环境而不是工具。让我们使用像 nock 这样的 HTTP 拦截器编写一个测试。这样做的好处是您可以迁移到不同的数据获取工具或更改获取行为并从您的测试中获得反馈。

// src/SearchContainer/SearchContainer.test.js
import React from "react";
import nock from "nock";
import mount from "enzyme";

import Search from "../../components/Search";
import  API_KEY  from "../../../config";

describe('<SearchContainer />', async () => 
  it('searches for articles', () => 
    const scope = nock('http://content.guardianapis.com')
      .get('/search')
      .query('api-keys': API_KEY, q: 'some article')
      .reply(200, 
        results: [...]
      )
    const wrapper = mount(<SearchContainer />);
    const searchInput = wrapper.find('[data-test-id="search-input"]');
    await searchInput.simulate('change',  target:  value: 'some article'  );
    const articles = wrapper.find('[data-test-id="articles"]');
    expect(articles.length > 0).toBe(true);
    expect(scope.isDone()).toBe(true);
  );
);

为了更深入地了解测试 API 调用,我写了一篇博文 Testing Components that make API calls。

【讨论】:

以上是关于如何使用 jest 和酶测试 API 调用?的主要内容,如果未能解决你的问题,请参考以下文章

如何在构造函数内部使用上下文的情况下使用 jest 和酶来测试反应上下文?

Jest和酶有啥区别?

使用 Jest 和酶时如何在 React.useEffect 钩子上获得线路覆盖?

TypeError:使用 react-create-app jest 和酶进行测试时,调度不是函数

带有笑话和酶的反应单元测试

如何模拟在使用 Jest 测试的 React 组件中进行的 API 调用