【React高级】 数据获取然后进行创建测试(使用多渲染器以及计时器)

简介: 【React高级】 数据获取然后进行创建测试(使用多渲染器以及计时器)

@[toc]

创建

对于每个测试,我们通常都希望将React树呈现给附加到文档的DOM元素。这很重要,因为它可以接收DOM事件。测试完成后,我们需要“清理”并从文档中卸载树。

import { unmountComponentAtNode } from "react-dom";

let container = null;
beforeEach(() => {
  // 创建一个 DOM 元素作为渲染目标
  container = document.createElement("div");
  document.body.appendChild(container);
});

afterEach(() => {
  // 退出时进行清理
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

一种常见的方法是使用一对beforeEach和afterEach块来保持它们运行并隔离测试本身的影响。

act(() => {
  // 渲染组件
});
// 进行断言

这有助于在使用应用程序时使测试运行更接近真实用户体验。这些示例的其余部分使用act()进行这些保证。
可能会发现直接使用act()有点过于冗长。为了避免一些样板代码,可以使用React测试库。这些助手使用act()函数封装。


import React from "react";

export default function Hello(props) {
  if (props.name) {
    return <h1>你好,{props.name}!</h1>;
  } else {
    return <span>嘿,陌生人</span>;
  }
}

数据获取

可以使用假数据模拟请求,而不是在所有测试中调用真实的API。使用“假”数据模拟数据采集可以防止由于后端不可用而导致的不稳定测试,并使其运行更快。注意:可能仍然希望使用“端到端”框架运行测试子集,以显示整个应用程序是否协同工作。


import React, { useState, useEffect } from "react";

export default function User(props) {
  const [user, setUser] = useState(null);

  async function fetchUserData(id) {
    const response = await fetch("/" + id);
    setUser(await response.json());
  }

  useEffect(() => {
    fetchUserData(props.id);
  }, [props.id]);

  if (!user) {
    return "加载中...";
  }

  return (
    <details>
      <summary>{user.name}</summary>
      <strong>{user.age}</strong> 岁
      <br />
      住在 {user.address}
    </details>
  );
}
import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";
import User from "./user";

let container = null;
beforeEach(() => {
  // 创建一个 DOM 元素作为渲染目标
  container = document.createElement("div");
  document.body.appendChild(container);
});

afterEach(() => {
  // 退出时进行清理
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

it("渲染用户数据", async () => {
  const fakeUser = {
    name: "Joni Baez",
    age: "32",
    address: "123, Charming Avenue"
  };
  jest.spyOn(global, "fetch").mockImplementation(() =>
    Promise.resolve({
      json: () => Promise.resolve(fakeUser)
    })
  );

  // 使用异步的 act 应用执行成功的 promise
  await act(async () => {
    render(<User id="123" />, container);
  });

  expect(container.querySelector("summary").textContent).toBe(fakeUser.name);
  expect(container.querySelector("strong").textContent).toBe(fakeUser.age);
  expect(container.textContent).toContain(fakeUser.address);

  // 清理 mock 以确保测试完全隔离
  global.fetch.mockRestore();
});

某些模块在测试环境中可能无法正常工作,或者对测试本身不重要。用虚拟数据模拟这些模块,更容易为代码编写测试。

多渲染器

在极少数情况下,可能在使用多个渲染器的组件上运行测试。例如, 可能正在内部使用ReactDOM的react测试渲染器组件上运行快照测试。在子组件中渲染以渲染某些内容。在此场景中,可以使用与其渲染器对应的动作()来包装更新。

import { act as domAct } from "react-dom/test-utils";
import { act as testAct, create } from "react-test-renderer";
// ...
let root;
domAct(() => {
  testAct(() => {
    root = create(<App />);
  });
});
expect(root).toMatchSnapshot();

计时器

代码可能使用基于计时器的函数(如setTimeout)来安排将来的更多工作。在此示例中,多选面板等待选择并向前移动。如果在5秒内没有选择,则超时:

import React, { useEffect } from "react";

export default function Card(props) {
  useEffect(() => {
    const timeoutID = setTimeout(() => {
      props.onSelect(null);
    }, 5000);
    return () => {
      clearTimeout(timeoutID);
    };
  }, [props.onSelect]);

  return [1, 2, 3, 4].map(choice => (
    <button
      key={choice}
      data-testid={choice}
      onClick={() => props.onSelect(choice)}
    >
      {choice}
    </button>
  ));
}

我们可以使用Jest的计时器模拟为这个组件编写测试,并测试它可能处于的不同状态。

import React from "react";
import { render, unmountComponentAtNode } from "react-dom";
import { act } from "react-dom/test-utils";

import Card from "./card";

jest.useFakeTimers();

let container = null;
beforeEach(() => {
  // 创建一个 DOM 元素作为渲染目标
  container = document.createElement("div");
  document.body.appendChild(container);
});

afterEach(() => {
  // 退出时进行清理
  unmountComponentAtNode(container);
  container.remove();
  container = null;
});

it("超时后应选择 null", () => {
  const onSelect = jest.fn();
  act(() => {
    render(<Card onSelect={onSelect} />, container);
  });

  // 提前 100 毫秒执行
  act(() => {
    jest.advanceTimersByTime(100);
  });
  expect(onSelect).not.toHaveBeenCalled();

  // 然后提前 5 秒执行
  act(() => {
    jest.advanceTimersByTime(5000);
  });
  expect(onSelect).toHaveBeenCalledWith(null);
});

it("移除时应进行清理", () => {
  const onSelect = jest.fn();
  act(() => {
    render(<Card onSelect={onSelect} />, container);
  });
  act(() => {
    jest.advanceTimersByTime(100);
  });
  expect(onSelect).not.toHaveBeenCalled();

  // 卸载应用程序
  act(() => {
    render(null, container);
  });
  act(() => {
    jest.advanceTimersByTime(5000);
  });
  expect(onSelect).not.toHaveBeenCalled();
});

it("应接受选择", () => {
  const onSelect = jest.fn();
  act(() => {
    render(<Card onSelect={onSelect} />, container);
  });

  act(() => {
    container
      .querySelector("[data-testid='2']")
      .dispatchEvent(new MouseEvent("click", { bubbles: true }));
  });

  expect(onSelect).toHaveBeenCalledWith(2);
});

只能在某些测试中使用假计时器。上面,我们调用jestUseFakeTimers()来启用它们。它们提供的主要优点是,的测试实际上不需要等待5秒才能执行,并且不需要使组件代码更复杂地进行测试。

相关文章
|
1月前
|
消息中间件 存储 测试技术
【消息队列开发】 实现MemoryDataCenterTests类——测试管理内存数据
【消息队列开发】 实现MemoryDataCenterTests类——测试管理内存数据
|
16天前
|
数据采集 DataWorks 安全
DataWorks产品使用合集之选择独享调度,数据集成里可以使用,但是数据地图里面测试无法通过,是什么原因导致的
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
16 0
DataWorks产品使用合集之选择独享调度,数据集成里可以使用,但是数据地图里面测试无法通过,是什么原因导致的
|
25天前
|
人工智能 分布式计算 DataWorks
首批!阿里云 MaxCompute 完成中国信通院数据智能平台专项测试
2024年5月31日,在中国信通院组织的首批数据智能平台专项测试中,阿里云数据智能平台解决方案(MaxCompute、DataWorks、PAI)顺利完成测试。
102 5
首批!阿里云 MaxCompute 完成中国信通院数据智能平台专项测试
|
1天前
|
机器学习/深度学习 运维 算法
Doping:使用精心设计的合成数据测试和评估异常检测器的技术
在这篇文章中,我们将探讨测试和评估异常检测器的问题(这是一个众所周知的难题),并提出了一种解决方案被称为“Doping”方法。使用Doping方法,真实数据行会被(通常是)随机修改,修改的方式是确保它们在某些方面可能成为异常值,这时应该被异常检测器检测到。然后通过评估检测器检测Doping记录的效果来评估这些检测器。
10 0
|
29天前
|
数据可视化 数据挖掘 定位技术
在服务中收集和测试数据
【6月更文挑战第16天】本文讨论了数据收集和测试的重要性,指出样本量应根据时间和预算调整。数据分析涉及比较结果与假设,可视化数据以增强理解,并通过统计测试确认显著性。设计的持续优化是关键,适应变化的业务、技术和用户需求,数据驱动的方法能提供最佳用户体验。
25 5
在服务中收集和测试数据
|
18天前
|
存储 测试技术
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
29 0
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
|
19天前
|
存储 测试技术 Python
记一次线上安全测试中误用父类属性导致数据污染的解决方案
在线上安全测试的过程中,会使用 Nmap 进行端口扫描,为了提升端口扫描的效率,扫描策略通常是检测常用端口是否处于开放状态,并在父类中使用名为 all_open_ports 的属性来记录这些开放的端口。 在后续的测试过程中,需要检查所涉及的端口是否包含在 all_open_ports 中。如果不存在,就需要进一步对这些端口进行开放检测。如果端口的检测结果是开放的,测试将继续进行并将这些端口记录到 all_open_ports 中,以便在下次遇到相同端口时无需重复检测。 然而,由于安全测试是多线程进行的,某些情况下可以将 all_open_ports 理解为共享变量,这导致当两个不同的测试环境同
|
29天前
|
前端开发 JavaScript 测试技术
Jest与React Testing Library:前端测试的最佳实践
Jest和React Testing Library是React应用测试的核心工具。安装相关依赖后,在`jest.config.js`中配置Jest。测试时,编写描述性测试用例,使用`render`、`fireEvent`和`screen`来检查组件行为。Jest提供模拟功能,如模拟API调用。测试组件交互性时,模拟用户行为并验证状态变化。确保覆盖边缘情况,使用代码覆盖率报告评估测试完整性,并将测试集成到CI流程中。
21 1
|
10天前
|
前端开发 JavaScript 算法
react【框架原理详解】JSX 的本质、SyntheticEvent 合成事件机制、组件渲染过程、组件更新过程
react【框架原理详解】JSX 的本质、SyntheticEvent 合成事件机制、组件渲染过程、组件更新过程
13 0
|
11天前
|
JSON 数据格式
Navicate数据报错之Bad Request,发送端口测试的时候,使用JSON字符串,而不是Text
Navicate数据报错之Bad Request,发送端口测试的时候,使用JSON字符串,而不是Text

相关实验场景

更多