【问题标题】:How to test Async calls in JEST using request without mocking and awaits for react-hooks testing library如何使用请求在 JEST 中测试异步调用而不使用模拟和等待 react-hooks 测试库
【发布时间】:2021-10-14 09:30:04
【问题描述】:

就非 API 功能而言,我不擅长编写测试,我在 rendererHook 的帮助下使用 JEST 进行了测试,如下所示正确测试示例

import { render, screen, cleanup } from '@testing-library/react';
import useAppDrawer from "../../../utils/hooks/useAppDrawer";
import {act,renderHook} from '@testing-library/react-hooks';
import React from "react";

describe("hook: useAppDrawer", () => {

    afterEach(() => {
        cleanup();
    });

    test('drawer open', () => {
        const {result} = renderHook(useAppDrawer);

        act(()=>{
            result.current.handleDrawerOpen();
        })
        expect(result.current.open).toBe(true);

    });
    test('drawer close', () => {
        const {result} = renderHook(useAppDrawer);

        act(()=>{
            result.current.handleDrawerClose();
        })
        expect(result.current.open).toBe(false);

    });

});

但是,如果 JEST 中的 API 调用仍然让我感到困惑,我们该怎么办。我仍然无法理解如何在 JEST 中测试 API 调用,如下所示 Problematic function

import React, {useContext} from "react";
import request from "../services/Http";
import useIsLoading from "./useIsLoading";
import {Context} from "../store/context/store";
import {SET_BOOTHS} from "../store/context/Constants";

export default function useFetchBooths(){

    const {isLoading, setIsLoading} = useIsLoading()
    const [{booths}, dispatch] = useContext(Context)

    function fetchBooths(){

        setIsLoading(true)

        request.get('/event/get-booth-list')
            .then((res) => {
                setIsLoading(false)
                if (res)
                {
                    dispatch({
                        type: SET_BOOTHS,
                        payload: res.data.booth_data
                    })
                }
            })
    }

    function searchBooths(value){

        if (value)
        {
            let obj = booths.filter(booth => booth.booth_name.toLowerCase().includes(value.toLowerCase()));

            if (obj.length > 0)
            {
                dispatch({
                    type: SET_BOOTHS,
                    payload: obj
                })
            }
            else
            {
                fetchBooths()
            }

        }
        else
        {
            fetchBooths()
        }
    }

    return { booths, fetchBooths, isLoading, searchBooths }
}

上述函数可能的开玩笑测试是什么?考虑是否获取展位等情况,因为在这两种情况下,我都将展位价值设为 []。 到目前为止,我的尝试是:

import { render, screen, cleanup, waitFor } from '@testing-library/react';
import useFetchBooths from "../../../utils/hooks/useFetchBooths";
import {act,renderHook} from '@testing-library/react-hooks';
import React from "react";
import * as requestsModule from "../../../utils/services/Http";
import {Store} from "../../../utils/store/context/store";

describe("hook: useFetchBooths", () => {

    afterEach(() => {
        cleanup();
    });

    test('Booth is fetched', async () => {
        const boothData = [
            {
                "message": "Data fetched Successfully",
                "success": true
            }
        ];
        const wrapper = ({children}) => (
            <Store>{children}</Store>
        )
        const {result } = renderHook(() => useFetchBooths(), {wrapper});
         jest.spyOn(result.current, "fetchBooths").mockResolvedValue(boothData);
         console.log(result.current.fetchBooths())
        await expect(result.current.fetchBooths()).resolves.toEqual([{ "success": true, "message": "Data fetched Successfully" }]);

    });

});

上面的测试用例通过了,但这是一个模拟的 API(我正在创建数据并将其与我自己的书面数据进行比较,但这不是我想要的)但我想确保我的真实 API 是否正常工作测试就像我在 fetchBooths() 函数中获取展位列表一样,所以当我的一切都依赖于真实 API 时,如何使用模拟 API 对其进行测试async/await 但我在这一点上陷入了困境。另外,我无法理解 searchBooths 功能的测试用例是什么,因为它显示为未定义,并且展位列表显示为 [] 虽然它不应该是 [] 我仍然无法计算出解决方案。请帮我写这些测试用例

【问题讨论】:

  • 你想在这里测试什么?我假设您对测试 makeStyles 本身不感兴趣
  • @thedude 我仍然无法理解我们如何在 JEST 中为 API 调用编写测试。就像我在上面写的函数 fetchBooths() 一样,考虑到是否已获取展位等情况,我如何为其编写测试,因为在这两种情况下,我都将展位值设为 []。
  • @thedude 我已经更新了这个问题。你现在能帮帮我吗?
  • 我会查看 jest.spyOn 来模拟 request.get 并断言它已被正确输入调用。可以采用相同的方法来测试makeStyles
  • @thedude 能否请您详细说明一下,例如纠正我尝试的代码,考虑到我上面的尝试,例如我可以进入 fetchBooths setLoading(true) 但无法从请求中获取任何内容。如果可能,请告诉我,以便我可以与您共享我的屏幕?

标签: testing jestjs react-hooks automated-tests react-hooks-testing-library


【解决方案1】:

在您的测试代码中使用spy 模拟请求模块:

import * as requestsModule from "../services/Http";

describe("hook: useFetchBooths", () => {

    afterEach(() => {
        cleanup();
    });

    test('Booth is fetched', async () => {

        jest.spyOn(requestsModule, 'get').mockResolvedValue([]) // <-- here you should provide the data you want your hook to see.

        const wrapper = ({children}) => (
            <Store>{children}</Store>
        )

        const {result } = renderHook(() => useFetchBooths(), {wrapper});
        await act(async () => {
            await waitFor(() => result.current.fetchBooths() )
        })

        await act(async () => {
            await waitFor(() => result.current.booths )
            console.log(result.current);
        })
        expect(result.current.booths).toEqual([]);

    });

});

更新:如何模拟 useContext

  1. 创建自定义挂钩
// boothsContext.js

import {Context} from "../store/context/store";

export const useBoothsContext = () => useContext(Context)

  1. 使用jest.spyOn模拟钩子:
import { wait } from '@testing-library/react'
import * as BoothsContextModule from './boothsContext.js'

...

test('Booth is fetched', async () => {
    const mockDispatch = jest.fn()
    const data = { booths: []} // change this to inject different data into your hook result
    jest.spyOn(BoothsContextModule, 'useBoothsContext')
        .mockReturnValue([data, mockDispatch])

    // perform test steps

   await wait(() => expect(mockDispatch).toHaveBeenCalledWith({
      type: SET_BOOTHS,
      payload: {...} // <-- expected payload you want to assert
   }))

【讨论】:

  • 我不能只检查是否获取数据并获得“消息”:“成功获取数据”,然后我就通过了测试?我应该如何在 JEST 中实现这一点?
  • 我正在传递数据,例如 jest.spyOn(requestsModule, 'get').mockResolvedValue({data:{"success": true, "message": "Data fetched Successfully"},"booth_data ": [ { "booth_id": "8818", "booth_name": "Advanis 已更改", }] });但我陷入了错误“错误:无法监视 get 属性,因为它不是函数;改为未定义”
  • 如何将这些模拟值与实际值进行比较,以便通过将原始数据与模拟数据进行比较来添加“预期条件”以传递?您能否更新 searchBooths 和 fetchBooths 函数的答案,包括为通过测试应满足的预期条件,我将非常感谢您。如果你问我可以通过 TeamViewer 或其他方式与你共享我的屏幕
  • 我仍然卡住了我已经根据您的指导更新了我的尝试,如果我们只是在模拟 API,那么我们将如何测试实际的真实 API 是否正常工作我还想通过使用某种异步等待来确保我真正的 API 在我主要关心的功能测试中工作。另外,searchBooths 函数的测试用例是什么我在编写该测试时也感到困惑,我已经提到了这个有问题的文件,我想为其编写测试的粗体名称“Problematic Function”。任何帮助将不胜感激
  • 看来您并没有真正编写单元测试。最佳实践是将代码分解为可以单独测试的单元。如果您想实际调用 API,那么您可以模拟 useContext 钩子并检查是否进行了正确的 dispatch 调用,而不是模拟 get 请求
猜你喜欢
  • 2020-03-24
  • 1970-01-01
  • 2021-07-29
  • 2020-08-16
  • 2019-04-22
  • 2021-06-14
  • 2014-07-20
  • 1970-01-01
  • 2021-06-04
相关资源
最近更新 更多