当前位置: 首页 > 编程日记 > 正文

react 快速上手开发_React中测试驱动开发的快速指南

react 快速上手开发

by Michał Baranowski

通过MichałBaranowski

React中测试驱动开发的快速指南 (A quick guide to test-driven development in React)

Following the principles of Test-Driven Development (TDD) when writing a front-end React app might seem more difficult than doing the same on the back-end.

编写前端时遵循测试驱动开发 (TDD)的原理 React应用程序似乎比在后端执行相同的操作更加困难。

First, we need to somehow render our component. Then we need to simulate user interaction with a browser. Next we respond to changes in props and state, and finally come up with a way to test asynchronous methods triggered by the click of a button.

首先,我们需要以某种方式呈现我们的组件。 然后,我们需要模拟用户与浏览器的交互。 接下来,我们响应道具状态的变化最后提出一种方法来测试单击按钮触发的异步方法。

Trying to cover all these cases in our tests often results in tests that are difficult to read. They also often depend on one another. We mock a lot, and in return we have tests full of anti-patterns.

试图在我们的测试中涵盖所有这些情况通常会导致难以阅读的测试。 他们还经常相互依赖。 我们进行了很多模拟,作为回报,我们进行了充满反模式的测试。

不要浪费你的时间 (Don’t waste your time)

From what I’ve seen, many programmers create working React components first.Then they try to cover them with tests, just to realize that the components cannot be tested in their current implementation. Then they need to refactor. Because of that they lose patience, time, and their employer’s money.

从我所看到的来看,许多程序员首先创建了可工作的React组件,然后试图通过测试覆盖它们,只是为了意识到无法在当前实现中对组件进行测试。 然后他们需要重构。 因此,他们失去了耐心,时间和雇主的金钱。

可用的解决方案 (Available solutions)

Fortunately for us, there are many testing libraries that can help us address these problems. We can try rendering React components with Enzyme and mock API responses using MockAxios. However, these libraries usually have so many methods and options that it might get confusing, especially for people who have just started writing tests.

对我们来说幸运的是,有许多测试库可以帮助我们解决这些问题。 我们可以尝试使用MockAxios渲染带有酶的 React组件和模拟API响应。 但是,这些库通常具有太多的方法和选项,可能会引起混淆,特别是对于刚开始编写测试的人。

Let’s take Enzyme for example — what’s the difference between the Shallow, Mount and Render methods? And which should you use? This is not what you should be worried about when you write your tests, in my opinion. It should be as straight forward as possible.

让我们以为例-ShallowMountRender方法之间有什么区别? 您应该使用哪个? 我认为这不是编写测试时应该担心的。 它应该尽可能直接。

我们的项目 (Our project)

For our Quick Guide purposes, we’re going to create a small React app. After clicking on a button, a random joke about Chuck Norris will be fetched and displayed.

出于快速指南的目的,我们将创建一个小型React应用。 单击按钮后,将获取并显示有关Chuck Norris的随机笑话。

No one has ever pair-programmed with Chuck Norris and lived to tell about it.
从来没有人与Chuck Norris结对编程并活着讲述这件事。

So let’s begin.

因此,让我们开始吧。

Kick-off by creating a React project in CodeSandbox, and then install the following dependencies (Jest is already pre-installed if you started from the link above):

开球创建一个阵营项目CodeSandbox 然后安装以下依赖性(j EST 如果您从上面的链接开始,则已经预先安装了):

  • axios — used for fetching data from the external API

    axios-用于从外部API提取数据

  • axios-mock-adapter — used for mocking server responses

    axios-mock-adapter-用于模拟服务器响应

  • react-testing-library — light, easy to use testing library for rendering, simulating actions, and handling async methods — created by Kent C. Dodds

    React测试库 —轻巧,易于使用的测试库,用于渲染,模拟动作和处理异步方法—由Kent C. Dodds创建

  • jest — for running the tests and creating assertions

    笑话 —用于运行测试和创建断言

文件夹/文件结构 (Folder/files structure)

  • src/index.js — entry point for our React app

    src / index.js —我们的React应用程序的入口点

  • src/jokeGenerator.js our container component which fetches, controls, and provides data

    src / jokeGenerator.js 我们的容器组件,用于获取,控制和提供数据

  • src/joke.js — simple presentation component

    src / joke.js —简单的演示组件

  • src/__tests__/jokeGenerator.test.js contains our tests

    src / __ tests __ / jokeGenerator.test.js 包含我们的测试

您的第一个测试 (Your first test)

Each time before we create a component we will write a failing test first and then try to make it pass. Let’s start by writing a test for our dummy component <Joke /> which will render a text from props.

每次创建组件之前,我们都会先编写一个失败的测试,然后尝试使其通过 。 让我们首先为虚拟组件<Joke />编写一个测试,该测试将通过props渲染文本。

Reading from the top: we use a render method from the react-testing-library and pass the &lt;Joke/> component (which does not exist at this point) into it. It returns an object containing a few very useful methods (find the full list of available methods here) — for example getByTestId. It then returns an HTML element based on data-testid as an argument.

从顶部开始阅读:我们使用react-testing-library中的render方法,并将& lt; Jok e />组件(目前不存在)传递给它。 它返回一个包含了一些非常有用的方法的对象(可以找到我的完整列表的ThOD这儿) -为前充足getBy TestId。 然后,它返回基于data-t estidHTML元素作为参数。

Next, we write an expect using above method and data-testid, and check if the element contains the text from props. After running the tests, we get:

接下来,我们写一个想到利用上述方法和数据testid,并检查元素都包含道具的文字。 运行测试后,我们得到:

Joke is not defined
笑话未定义

Yep, we want it to fail! <Joke /> does not exist yet, remember? We have only created an empty joke.js file so far. We wrote a test in which we can clearly see what we expect the component to do. Now our job is to make the test pass without modifying the test code. Let’s do that then:

是的,我们希望它失败! <笑话 />还不存在,记得吗? 我们只创建了一个空的乔 ke.j S档为止。 我们编写了一个测试,可以清楚地看到我们期望组件执行的测试。 现在,我们的工作是使测试通过而无需修改测试代码。 然后让我们这样做:

Now, if you did everything just like I did, the test should pass :)

现在,如果您像我一样做所有事情,则测试应该通过:)

第二部分 (Second component)

Our second component will be responsible for fetching a random joke after a user clicks a button. We’ll save it in the component’s state and pass it down to our <Joke /> component. We would also like to display a default message when no joke has been loaded yet.

我们的第二个组件将负责在用户单击按钮后获取一个随机笑话。 我们将其保存为组件状态,并将其传递给我们的<Joke />组件。 当还没有玩笑时,我们还想显示一个默认消息。

Of course, we start with test first. It is a bigger component, so we’ll be writing the test step-by-step. We’ll also make sure it is passing as often as possible.

当然,我们首先要进行测试。 它是一个更大的组件,因此我们将逐步编写测试。 我们还将确保它尽可能多地通过。

We are already familiar with the render method, but this time we are taking getByText from the return object. As you might have guessed, the method returns an HTML Element if one exists in the DOM.

我们已经熟悉了render方法,但是这次我们从返回对象中获取getByText 。 您可能已经猜到了,如果DOM中存在HTML元素,该方法将返回一个HTML元素。

Run the tests and….

运行测试,然后…。

JokeGenerator is not defined
未定义JokeGenerator

You know what to do with it:

您知道如何处理它:

The test is still failing, but this time it outputs a different error:

测试仍然失败,但是这次它输出另一个错误:

Unable to find an element with the text.
找不到带有文本的元素。

You haven’t loaded any jokes yet. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

您还没有玩笑 。 这可能是因为文本被多个元素分解了。 在这种情况下,您可以为文本匹配器提供一个功能,以使匹配器更加灵活。

Let’s quickly fix that by introducing a state to our component and displaying a default message when there is no joke in the state.

让我们快速解决该问题,方法是在组件中引入一个状态并在该状态中没有笑话时显示默认消息。

Tests are passing now, so we can move on to add new functionality. Imagine that when we click on a button, the default text in the component disappears to make room for a “Loading…” message. Sounds pretty straightforward, right? We can test this scenario with only three lines of code!

测试现已通过,因此我们可以继续添加新功能。 想象一下,当我们单击一个按钮时,组件中的默认文本消失了,从而为“ 正在加载... ”消息腾出了空间。 听起来很简单,对吧? 我们可以只用三行代码测试此业务情景!

Let’s import the Simulate method first, as we’re going to need that:

首先,我们需要导入Simulate方法,因为我们需要这样做:

import { render, Simulate } from “react-testing-library”
从“ react-testing-library”导入{render,Simulate}

The difference between queryByText and getByText is in what each one returns when the element is not found. The first one returns null and the second one throws an error message. Re-running the tests:

queryByTextgetByText之间的区别在于,当找不到该元素时,每个返回的内容。 第一个返回null ,第二个返回错误消息 。 重新运行测试:

Unable to find an element with the text: Load a random joke

找不到带有文本的元素: 加载一个随机笑话

We need to create a button and set the onClick method which will set the loading state to true.

我们需要创建一个按钮并设置onClick方法,该方法会将加载状态设置为true

Just like that the test is passing again. Now it’s time to fetch our random joke! Well… it won’t be random in our tests. We’ll mock it using MockAxios.

就像测试再次通过一样。 现在是时候获取我们的随机笑话了! 好吧……在我们的测试中不会是随机的。 我们将使用MockAxios对其进行模拟

import * as axios from "axios"

从“ axios”将*作为axios导入

Above our tests in jokeGenerator.test.js, insert these two lines of code:

jokeGenerator.test.js中的测试上方,插入以下两行代码:

The first line creates a new instance of MockAxios with a random delay. The second line takes and executes a callback function after running all the tests in this file, and removes the mocked state from axios.

第一行创建一个随机延迟的MockAxios新实例。 第二行在运行此文件中的所有测试之后,采用并执行回调函数,并从axios中删除模拟状态。

At the top of our second test where we test the <JokeGenerator /> component, add:

在我们测试<JokeGenerator />组件的第二个测试的顶部,添加:

It mocks the response of any GET call done via axios. At the end of the same test:

模拟了通过axios完成的任何GET调用的响应。 在同一测试结束时:

Don’t forget to import wait:

不要忘记导入wait

import { render, Simulate, wait } from “react-testing-library”
从“ react-testing-library”导入{渲染,模拟,等待}

The wait method waits (4500ms by default) until a callback function stops throwing an error. It is checked at 50ms intervals. Basically we’re just waiting until the loading message disappears from the DOM.

wait方法等待(默认为4500ms),直到回调函数停止引发错误为止。 每隔50毫秒检查一次。 基本上,我们只是在等待加载消息从DOM中消失。

wait is also available as a separate npm package (react-testing-library uses it as a dependency). It was created by Łukasz Gozda Gandecki.

wait也可以作为单独的npm包提供 ( react-testing-library使用它作为依赖项)。 它是由ŁukaszGozda Gandecki创建的。

After making all of the code modifications and running the tests, we should get the following fail message:

在完成所有代码修改并运行测试之后,我们应该获得以下失败消息:

Expected the element not to be present

预期该元素存在

What do you think it might be? According to our test, we expect the loading message to be gone. Additionally, we want to fetch our joke from the API and save it to the state so that next expect passes.

您认为可能是什么? 根据我们的测试,我们希望加载消息消失。 另外,我们想从API中获取笑话并将其保存到状态,以便下次期望通过。

Tests should pass again now. We are sure that everything works as expected…aren’t we? Notice that we have never opened our browser and verified manually if our app even works…However, thanks to how we were writing our tests (so that our tests resemble the way the user would use the application), we can be almost 100% sure that our small app is simply working.

现在应该再次通过测试。 我们确信一切都会按预期进行,对吗? 请注意,我们从未打开过浏览器并手动验证过我们的应用程序是否可以正常工作 ……但是,由于我们编写测试的方式( 使我们的测试类似于用户使用应用程序的方式 ),我们几乎可以百分百确定我们的小型应用程序只是在工作。

As the last piece of code, let’s add this to the index.js and open the browser :)

作为最后的代码,让我们将其添加到index.js并打开浏览器:)

奖金 (Bonus)

Because of the way we wrote our tests, we can utilize them as e2e tests without adding a single line of code! All we need to do is to remove all the lines related to MockAxios and run the tests again! They will now use a real external API. Cool, isn’t it? :)

由于我们编写测试的方式,我们可以将它们用作e2e测试, 而无需添加任何代码! 我们要做的就是删除所有与MockAxios相关的行, 然后再次运行测试! 他们现在将使用真正的外部API。 不错,不是吗? :)

摘要 (Summary)

All the code is available on the project’s CodeSandbox. I really encourage you to get familiar with a full react-testing-library documentation. You’ll find there many more examples and use cases.

所有代码都可以在项目的CodeSandbox上找到 我真的鼓励您熟悉完整的react-testing-library文档。 您会发现更多示例和用例。

I hope you enjoyed my Quick Guide to TDD in React, and that you’ve learned something new today.

希望您喜欢React中的TDD快速指南,并且今天学到了新知识。

翻译自: https://www.freecodecamp.org/news/quick-guide-to-tdd-in-react-81888be67c64/

react 快速上手开发

相关文章:

iOS 相册和网络图片的存取

iOS 相册和网络图片的存取 保存 UIImage 到相册 UIKit UIKit 中一个古老的方法&#xff0c;Objective-C 的形式 void UIImageWriteToSavedPhotosAlbum(UIImage *image, id completionTarget, SEL completionSelector, void *contextInfo); 保存完成后&#xff0c;会调用 comple…

微信小程序实时聊天之WebSocket

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 1.所有监听事件先在onload监听。 // pages/index/to_news/to_news.js var app getApp(); var socketOpen false; var SocketTask false; var url ws://192.168.0.120:7011; Page…

webform repeater

repeater:由模板构成&#xff0c;解析后模板就不存在了 需要指定数据源进行数据绑定 List<Fruit> list new FruitDA().Select(); // 数据查询 &#xff08;随便查寻的&#xff09; Repeater1.DataSource list; // 赋值 Repeater1…

远程协助软件开发_这是我从事远程软件开发人员工作的主要技巧

远程协助软件开发by Colin Morgan通过科林摩根(Colin Morgan) 这是我从事远程软件开发人员工作的主要技巧 (Here are the top tips I’ve used to land a remote software developer job) Applying for a remote software developer job means you are voluntarily choosing t…

简谈-Python一些常用的爬虫技巧

第一种&#xff1a;基本的网页抓取 get方法 import urllib2url "链接response urllib2.urlopen(url)print response.read() post方法 import urllibimport urllib2url "链接form {name:abc,password:1234}form_data urllib.urlencode(form)request urllib2.Req…

微信小程序画布圆形进度条demo

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; wxml <!--pages/test/test.wxml--> <canvas style"width: 300px; height: 200px;" canvas-id"canvasid"></canvas>js // pages/test/test.js …

smarty 模板引擎

http://blog.csdn.net/zuiaituantuan/article/details/5951242 http://wenku.baidu.com/link?url-UHlSnTXOOAjFG1KjX6T9sEG6V4hNAMfRDpMuRRnc_FKbFAxiE5Ntk4lzxSm-7Z531uWdfvgYx81sdC61SgTZm7q8FdUt3gSs7ZlC0JR1SW转载于:https://www.cnblogs.com/hxjbc/p/4441879.html

flask url构建_如何为生产构建构建Flask-RESTPlus Web服务

flask url构建by Greg Obinna由格雷格奥比纳(Greg Obinna) 如何为生产构建构建Flask-RESTPlus Web服务 (How to structure a Flask-RESTPlus web service for production builds) In this guide I’ll show you a step by step approach for structuring a Flask RESTPlus web…

【2017-4-26】Winform 公共控件 菜单和工具栏

作废 等待重写 名称 功能取值赋值备注Button按钮多用来触发点击事件 CheckBox多选按钮 CheckedListBox多选按钮组 ComboBox下拉列表 DateTimePicker指定的格式选择时间日期 Lable说明性文字控件 LinkLable超链接类型文件控件 ListBox用户选择项 ListVie…

微信小程序限制当前位置和目的地的距离

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 1。获取当前位置经纬度 onLoad: function (options) {var that this;campaign_id campaign_idwx.getLocation({type: wgs84,success: function (res) {console.log(res)lat1 res.l…

命令行的全文搜索工具--ack

想必大家在命令行环境下工作时候&#xff0c;一定有想要查找当前目录下的源代码文件中的某些字符的需求&#xff0c;这时候如果使用传统方案&#xff0c;你可能需要输入一长串的命令&#xff0c;比如这样&#xff1a; 1. grep -R string dir/ 或者 grep -r -e string direct…

ecmascript_TC39及其对ECMAScript的贡献

ecmascriptby Parth Shandilya通过Parth Shandilya TC39及其对ECMAScript的贡献 (TC39 and its contributions to ECMAScript) Many people get confused about what is JavaScript and what is ECMAScript. Sometimes it’s hard to tell how they are connected with each o…

Winio驱动在64位windows下无法使用的解决方法

C#在使用WinIo的驱动开发类似按键精灵一类工具的时候&#xff0c;需要对相关的驱动进行注册才能正常启动&#xff0c;找了下资料&#xff0c;资料来自&#xff1a; http://jingyan.baidu.com/article/642c9d34e55bd9644b46f74e.html 我在这里进行转载&#xff1a; Winio驱动在6…

js获取前后几天或者前后几个月的日期

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 &#xff1b; 正文&#xff1a; demo: 1.获取前后几天的日期 // pages/test/test.jsPage({onLoad: function (options) {var day -7;console.log(GetDay(day))}, }) function GetDay(day) {var tim…

nodejs安装、配置及开发工具

学了node一段时间&#xff0c;但是node的安装还是有一点迷糊。今天新换电脑&#xff0c;所以&#xff0c;需要从头开始&#xff0c;发现node的安装还是不顺畅&#xff0c;这篇随笔是之前学的时候写&#xff0c;但是今天再打开看的时候&#xff0c;发现其他好像没有什么内容&…

拨测工具_您可以拨多少钱? 快速简单地介绍有用的工具。

拨测工具by Miguel Bustamante通过Miguel Bustamante 您可以卷曲多少&#xff1f; 快速简单地介绍有用的工具。 (How much can you cURL? A quick and easy intro to a useful tool.) On a good day I can flex a 20 lb weight…twice. Probably. But that’s not the type o…

leetcode第一刷_Recover Binary Search Tree

这是一道好题&#xff0c;思路尽管有&#xff0c;可是提交之后总是有数据过不了&#xff0c;又依照数据改改改。最后代码都没法看了。收到的教训是假设必须为自己的代码加上非常多非常多特殊的限定。来过一些特殊的数据的话。说明代码本身有非常大的漏洞。 这道题&#xff0c;我…

Java中的文件路径

通常情况下&#xff0c;在Java项目中&#xff0c;我们使用的路径都是在拿到类加载路径后&#xff0c;根据相对位置&#xff0c;使用 FilePathTest.class.getResourceAsStream(relativePath)&#xff1b;拿到文件。今天小生不使用classPath&#xff0c;而是直接去使用相对路径来…

js上传文件,上传表单demo 包含后端php

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><title>Title</title><script src"https://ajax.as…

如何在Tensorflow.js中处理MNIST图像数据

by Kevin Scott凯文斯科特(Kevin Scott) 如何在Tensorflow.js中处理MNIST图像数据 (How to deal with MNIST image data in Tensorflow.js) There’s the joke that 80 percent of data science is cleaning the data and 20 percent is complaining about cleaning the data …

常用图像额文件格式及类型

1、显示一幅二值图像&#xff1a; >> bw zeros(90,90); >> bw(2:2:88,2:2:88) 1; >> imshow(bw); >> 2、利用image函数显示一幅索引图像&#xff1a; >> [X,MAP] imread(E:\STUDY_software\Matlab2016\images\11.jpg); >> image(X); &…

微信小程序实现滑动翻页效果源码附效果图

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 微信小程序实现滑动翻页效果 效果图&#xff1a; 源码&#xff1a; <view class"mainFrame"><swiper class"container" indicator-dots"{{indic…

Ubuntu 系统 文件操作命令

文件和目录的操作 用户主目录下有一个 Desktop (对应,桌面)mkdir dir1 建立一个目录cd 不添加参数,默认回到主目录(用户目录)touch a.txt 建立一个文件mv a.txt Desktop/ 移动到Desktop/中 mkdir dir1cp -r dir1/ dir2 不加-r或者&#xff0d;R的时候&#xff0c;只拷贝文件&am…

firebase 推送_如何使用Firebase向Web应用程序添加推送通知?

firebase 推送by Leonardo Cardoso由莱昂纳多卡多佐(Leonardo Cardoso) 如何使用Firebase向Web应用程序添加推送通知&#xff1f; (How to add push notifications to a web app with Firebase ??) As web applications evolve, it is increasingly common to come across f…

lucene构建同义词分词器

lucene4.0版本号以后 已经用TokenStreamComponents 代替了TokenStream流。里面包含了filter和tokenizer 在较复杂的lucene搜索业务场景下&#xff0c;直接网上下载一个作为项目的分词器&#xff0c;是不够的。那么怎么去评定一个中文分词器的好与差&#xff1a;一般来讲。有两个…

正则匹配出字符串中两串固定字符区间的所有字符

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 正文&#xff1a; 效果&#xff1a;匹配两个字符串区间的字符串 代码&#xff1a; var dd[];var str is_img"https://www.baidu.com/"is_img11is_img"https://www.baidu.com/"is…

识别手写字体app_我如何构建手写识别器并将其运送到App Store

识别手写字体app从构建卷积神经网络到将OCR部署到iOS (From constructing a Convolutional Neural Network to deploying an OCR to iOS) 项目动机✍️?? (The Motivation for the Project ✍️ ??) While I was learning how to create deep learning models for the MNIS…

20155307 2016-2017-2 《Java程序设计》第10周学习总结

20155307 2016-2017-2 《Java程序设计》第10周学习总结 教材学习内容总结 网络编程&#xff1a;就是在两个或两个以上的设备(例如计算机)之间传输数据。程序员所作的事情就是把数据发送到指定的位置&#xff0c;或者接收到指定的数据。在发送和接收数据时&#xff0c;大部分的程…

WinForm 实现验证码

private void CheckIdentifyingCode() { Random r new Random(); string str ""; for (int i 0; i < 5; i) { int a r.Next(0, 10); str a;//将数字连接到一块 } Bitmap bm new Bitmap(150, 90);//创建位图对象 Graphics g Graphics.FromImage(bm);//在bm中…

微信小程序打开预览下载的文件

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 使用 wx.openDocument(obj) 方法预览 wx.downloadFile({url: http://example.com/somefile.pdf,success: function (res) {var filePath res.tempFilePathwx.openDocument({filePath: filePath,success…