作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.< / div >< / div >
戴夫是韩国市场上排名第一的安卓应用程序的创造者. 他擅长多种编程语言和框架.
< / div >< / div >以前在
在这篇文章中, 我们将使用测试驱动开发(TDD)从用户故事到开发来开发一个反应应用程序. 同样,我们将在TDD中使用开玩笑和酶. 完成本指南后,您将能够:
\n\n本文假设您具有反应的基本知识. 如果您是反应的新手,我建议您完成 官方教程 看看Toptal的2019 反应教程: 第1部分 和 第2部分.
\n\n我们将构建一个由一些UI组件组成的基本番茄定时器应用程序. 每个组件在相应的测试文件中都有一组单独的测试. 首先,我们可以 创建史诗和用户故事 根据我们的项目要求如下.
\n\n史诗 | \n用户故事 | \n验收标准 | \n
作为一个用户,我需要使用计时器,这样我就可以管理我的时间. | \n作为一个用户,我需要启动计时器,这样我就可以倒数我的时间. | \n确保用户能够: \n \n*启动计时器 \n*看到计时器开始倒数 \n \n即使用户多次点击开始按钮,计数时间也不应中断.\n | \n
\n | 作为一个用户,我需要停止计时器,这样我才能在需要的时候倒数我的时间. | \n确保用户能够: \n \n*停止定时器 \n*见计时器停止 \n \n即使用户多次单击停止按钮,也不会发生任何事情.\n | \n
\n | 作为一个用户,我需要重置计时器,这样我就可以从一开始倒计时我的时间. | \n确保用户能够: \n \n*重置定时器 \n*参见定时器重置为默认值 | \n
首先,我们将使用 创建反应应用 如下:
\n\n$ NPX create-react-app react-timer\n$ CD反应计时器\n$ NPM start\n
\n\n您将看到在URL处打开一个新的浏览器选项卡 http://localhost:3000. 你可以使用以下命令停止正在运行的反应应用 Ctrl + C.
\n\n\n\n$ npm i -D酶\n$ npm i -D react-test-renderer酶-adapter-react-16\n
\n\n同时,我们将添加或更新一个名为 setupTests.js 在 src 目录:
\n\n从“酶”中导入{configure};\n从'酶-适配器-反应-16 '中导入适配器;\n\n配置({adapter: new adapter ()});\n
\n\n自 创建反应应用 运行 setupTests.js 文件,它将执行并正确配置酶.
\n\n我们将编写变量和一个基本的CSS重置,因为我们想 CSS变量 在应用程序中全局可用. 我们将定义变量 root作用域. 定义变量的语法是使用自定义属性表示法, 每个变量都以-开头,后面跟着变量名.
\n\n导航到 指数.css 文件并添加以下内容:
\n\n:根{\n\t——font - family:宋体;\n}\n\nBody, div, p {\n\t保证金:0;\n\t填充:0;\n}\n
\n\n现在,我们需要将CSS导入到应用程序中. 更新索引.Js文件如下:
\n\n从“反应”中导入反应;\n从' react-dom '导入反应DOM;\n进口的./索引.css ';\n反应DOM.呈现(\n\t<反应.StrictMode>\n\t\t<应用程序 />\n\t反应.StrictMode>\n\t文档.getElementById(“根”)\n)\n
\n\n正如您可能已经知道的,TDD过程看起来是这样的:
\n\n因此, 我们将为浅渲染测试添加第一个测试,然后编写代码以通过测试. 添加一个新的规范文件 应用程序.规范.js to src /组件/应用程序 目录如下:
\n\n从“反应”中导入反应;\n从' enzyme '中导入{shallow};\n导入应用程序./应用程序”;\n\ndescribe(‘应用程序’, () => {\n\tit(‘应该 呈现一个 ’, () => {\n\t\tconst 浅容器<应用程序 />);\n\t\t期望(容器.找到(div).长度).toEqual (1);\n});\n});\n
\n\n然后,您可以运行测试:
\n\n$ NPM测试\n
\n\n您将看到测试失败.
\n\n现在,我们将继续创建应用程序组件以通过测试. 导航到 应用程序.jsx 在目录中 src /组件/应用程序 并添加如下代码:
\n\n从“反应”中导入反应;\n\nconst 应用程序 = () => ;\n\n导出默认应用程序;\n
\n\n现在,再次运行测试.
\n\n$ NPM测试\n
\n\n第一个测试现在应该通过了.
\n\n我们将创建一个文件 应用程序.css 在目录中 src /组件/应用程序 给应用程序组件添加一些样式,如下所示:
\n\n.容器{\n\t身高:100 vh;\n\t宽度:100大众;\n\t对齐项目:中心;\n\t显示:flex;\n\tjustify-content:中心;\n}\n
\n\n现在,我们准备将CSS导入到 应用程序.jsx 文件:
\n\n从“反应”中导入反应;\n进口的./应用程序.css ';\n\nconst 应用程序 = () => ;\n\n导出默认应用程序;\n
\n\n接下来,我们必须更新 指数.js 导入应用程序组件,如下所示:
\n\nimport 反应 from \"react\"\nimport 反应DOM from \"react-dom\"\nimport \"./索引.css\"\nimport 应用程序 from \"./components/应用程序/应用程序\"\nimport * as serviceWorker from \"./serviceWorker\"\n\n反应DOM.呈现(\n <反应.StrictMode>\n <应用程序 />\n 反应.StrictMode>,\n 文档.getElementById(\"root\")\n)\n\n//如果你想让你的应用离线工作,加载速度更快,你可以修改\n// 注销()到register(. 注意,这有一些缺陷.\n//了解service worker的更多信息:http://bit.ly / CRA-PWA\nserviceWorker.注销()\n
\n\n最后,应用程序将包含计时器组件,因此我们将更新 应用程序.规范.js 文件来检查应用中是否存在计时器组件. 也, 我们将在第一个测试用例之外声明容器变量,因为浅层渲染测试需要在每个测试用例之前完成.
\n\nimport 反应 from \"react\"\nimport { shallow } from \"enzyme\"\nimport 应用程序 from \"./应用程序\"\nimport 计时器 from \"../计时器/计时器\"\n\ndescribe(\"应用程序\", () => {\n 让容器\n\n beforeEach(() => (浅容器<应用程序 />)))\n\n it(\"应该 呈现一个 \", () => {\n 期望(容器.find(\"div\").长度).toEqual (1)\n })\n\n it(\"应该 render the 计时器 Component\", () => {\n 期望(容器.containsMatchingElement(<计时器 />)).toEqual(真正的)\n })\n})\n
\n\n如果你逃跑 npm测试
在这个阶段,测试将失败,因为计时器组件还不存在.
现在,我们要创建一个名为 计时器.规范.js 在一个名为 计时器 下 src /组件 目录.
\n\n此外,我们将添加浅渲染测试 计时器.规范.js 文件:
\n\nimport 反应 from \"react\"\nimport { shallow } from \"enzyme\"\nimport 计时器 from \"./计时器\"\n\ndescribe(\"计时器\", () => {\n 让容器\n\n beforeEach(() => (浅容器<计时器 />)))\n\n it(\"应该 呈现一个 \", () => {\n 期望(容器.find(\"div\").长度).toBeGreaterThanOrEqual (1)\n })\n})\n
\n\n正如预期的那样,测试将会失败.
\n\n接下来,让我们创建一个名为 计时器.jsx 并根据用户故事定义相同的变量和方法:
\n\n从' 反应 '中导入反应, {Component};\n\n类定时器扩展组件{\n 构造函数(道具){\n 超级(道具);\n 这.状态= {\n 分钟:25日\n 秒:0,\n \t 关:假\n };\n }\n\n 开始时间(){\n 控制台.日志(“启动计时器.');\n }\n\n stop计时器 () {\n 控制台.日志(“停止计时器.');\n }\n\n reset计时器 () {\n 控制台.日志(“重置计时器.');\n }\n\n render = () => {\n return ;\n };\n}\n\n导出默认定时器;\n
\n\n这应该能通过测试 应该 呈现一个 在 计时器.规范.js 文件,但测试 不应该 渲染计时器组件,因为我们还没有在应用组件中添加计时器组件.
我们将在 应用程序.jsx 像这样的文件:
\n\n从“反应”中导入反应;\n进口的./应用程序.css ';\n导入定时器../定时器/计时器”;\n\nconst 应用程序 = () => (\n \n <计时器 />\n \n);\n\n导出默认应用程序;\n
\n\n现在所有的测试都应该通过了.
\n\n我们将添加与计时器相关的CSS变量,并为较小的设备添加媒体查询.
\n\n更新文件 指数.css 如下:
\n\n:根{\n\t——timer-background-color: # FFFFFF;\n——timer-border: 1px solid #000000;\n\t——timer-height: 70%;\n\t——timer-width: 70%;\n}\n\nBody, div, p {\n\t保证金:0;\n\t填充:0;\n}\n\n@media screen 和 (max-width: 1024px) {\n\t:根{\n\t\t——timer-height: 100%;\n\t\t——timer-width: 100%;\n}\n}\n
\n\n同时,我们要创建 计时器.css 目录下的文件 组件/计时器:
\n\n.timer-容器 {\n\tbackground - color: var(——timer-background-color);\n\t边界:var(——timer-border);\n\t高度:var(——timer-height);\n\t宽度:var(——timer-width);\n}\n
\n\n我们必须更新 计时器.jsx 要导入 计时器.css 文件.
\n\nimport 反应, { Component } from \"react\"\nimport \"./计时器.css\"\n
\n\n如果你现在运行反应应用,你会在浏览器上看到一个带有边框的简单屏幕.
\n\n我们需要三个按钮: 启动、停止, 重置,因此我们将创建 计时器Button组件.
\n\n首先,我们需要更新 计时器.规范.js 文件以检查是否存在 计时器Button 组件中的 计时器 组件:
\n\nit(\"应该渲染计时器Button组件的实例吗\", () => {\n 期望(容器.find(\"计时器Button\").长度).toEqual (3)\n })\n
\n\n现在,我们加上 计时器Button.规范.js 文件在名为 计时器Button 下 src /组件 目录,让我们像这样将测试添加到文件中:
\n\nimport 反应 from \"react\"\nimport { shallow } from \"enzyme\"\nimport 计时器Button from \"./ 计时器Button\"\n\ndescribe(\"计时器Button\", () => {\n 让容器\n\n beforeEach(() => {\n 浅容器\n <计时器Button\n buttonAction ={开玩笑.fn()}\n buttonValue={\"\"}\n />\n )\n })\n\n it(\"应该 呈现一个 \", () => {\n 期望(容器.find(\"div\").长度).toBeGreaterThanOrEqual (1)\n })\n})\n
\n\n现在,如果运行测试,您将看到测试失败.
\n\n让我们创建 计时器Button.jsx 申请 计时器Button 组件:
\n\n从“反应”中导入反应;\n从“prop-types”中导入PropTypes;\n\nconst 计时器Button = ({ buttonAction, buttonValue }) => (\n \n);\n\n计时器Button.propTypes = {\n buttonAction: proptype.函数.isRequired,\n buttonValue: proptype.字符串.isRequired,\n};\n\n导出默认计时器Button;\n
\n\n如果你逃跑 npm测试
在这个阶段,测试 应该渲染计时器Button组件的实例吗 但是会失败,因为我们还没有将计时器Button组件添加到计时器组件中.
让我们导入 计时器Button 组件并添加三个 计时器Button 中的呈现方法中的组件 计时器.jsx:
\n\nrender = () => {\n 回报(\n \n \n \n <计时器Button buttonAction ={这.开始时间} buttonValue ={'开始'} />\n <计时器Button buttonAction ={这.stop计时器} buttonValue ={‘停止’} />\n <计时器Button buttonAction ={这.reset计时器} buttonValue ={“重置”} />\n \n \n );\n };\n
\n\n现在,该为计时器Button组件添加CSS变量了. 让我们加入变量 :根 范围: 指数.css 文件:
\n\n:根{\n ...\n\n ——button-border: 3px solid #000000;\n ——button-text-size: 2 em;\n}\n\n@media screen 和 (max-width: 1024px) {\n :根{\n \n …\n\n ——button-text-size: 4 em;\n }\n}\n
\n\n另外,让我们创建一个名为 计时器Button.css 在 计时器Button 目录下的 src /组件 目录:
\n\n.按钮容器{\n Flex: 1 1 auto;\n text-align:中心;\n 边距:0px 20px;\n 边界:var(——button-border);\n 字体大小:var(——button-text-size);\n}\n\n.按钮容器:{徘徊\n 光标:指针;\n}\n
\n\n让我们来更新 计时器Button.jsx 因此,进口 计时器Button.css 文件和显示按钮值:
\n\n从“反应”中导入反应;\n从“prop-types”中导入PropTypes;\n进口的./ 计时器Button.css ';\n\nconst 计时器Button = ({ buttonAction, buttonValue }) => (\n \n {buttonValue}
\n \n);\n\n计时器Button.propTypes = {\n buttonAction: proptype.函数.isRequired,\n buttonValue: proptype.字符串.isRequired,\n};\n\n导出默认计时器Button;\n
\n\n此外,我们需要更新 计时器.css 为了使三个按钮水平对齐,让我们更新 计时器.css 文件以及:
\n\n从“反应”中导入反应;\n从“prop-types”中导入PropTypes;\n进口的./ 计时器Button.css ';\n\nconst 计时器Button = ({ buttonAction, buttonValue }) => (\n \n {buttonValue}
\n \n);\n\n计时器Button.propTypes = {\n buttonAction: proptype.函数.isRequired,\n buttonValue: proptype.字符串.isRequired,\n};\n\n导出默认计时器Button;\n
\n\n如果你现在运行反应应用,你会看到如下画面:
\n\n\n\n我们将重构计时器,因为我们想实现这样的函数 开始时间, stop计时器, re开始时间, reset计时器. 让我们来更新 计时器.规范.js 文件:
\n\ndescribe('安装定时器', () => {\n 让容器;\n\n beforeEach(() => (容器 = mount(<计时器 />)));\n\n it('invokes 开始时间 when the start button is clicked', () => {\n Const spy = jest.spyOn(容器.实例(),“开始时间”);\n 容器.实例().forceUpdate ();\n 期望(间谍).toHaveBeenCalledTimes (0);\n 容器.找到('.启动时间”).第().模拟('点击');\n 期望(间谍).toHaveBeenCalledTimes (1);\n });\n\n it('invokes stop计时器 when the stop button is clicked', () => {\n Const spy = jest.spyOn(容器.实例(),“stop计时器”);\n 容器.实例().forceUpdate ();\n 期望(间谍).toHaveBeenCalledTimes (0);\n 容器.找到('.stop-timer”).第().模拟('点击');\n 期望(间谍).toHaveBeenCalledTimes (1);\n });\n\n it('invokes reset计时器 when the reset button is clicked', () => {\n Const spy = jest.spyOn(容器.实例(),“reset计时器”);\n 容器.实例().forceUpdate ();\n 期望(间谍).toHaveBeenCalledTimes (0);\n 容器.找到('.reset-timer”).第().模拟('点击');\n 期望(间谍).toHaveBeenCalledTimes (1);\n });\n});\n
\n\n如果运行测试,您将看到添加的测试失败,因为我们没有更新 计时器Button 组件没有. 让我们来更新 计时器Button 组件来添加click事件:
\n\nconst 计时器Button = ({ buttonAction, buttonValue }) => (\n buttonAction()}>\n {buttonValue}
\n \n);\n
\n\n现在,测试应该通过了.
\n\n中调用每个函数时的状态,我们将添加更多的测试 安装定时器 测试用例:
\n\nit('应该 change isOn 状态 true when the start button is clicked', () => {\n 容器.实例().forceUpdate ();\n 容器.找到('.启动时间”).第().模拟('点击');\n 期望(容器.实例().状态.关).toEqual(真正的);\n });\n\n it('应该 change isOn 状态 false when the stop button is clicked', () => {\n 容器.实例().forceUpdate ();\n 容器.找到('.stop-timer”).第().模拟('点击');\n 期望(容器.实例().状态.关).toEqual(假);\n });\n\n it('应该 change isOn 状态 false when the reset button is clicked', () => {\n 容器.实例().forceUpdate ();\n 容器.找到('.stop-timer”).第().模拟('点击');\n 期望(容器.实例().状态.关).toEqual(假);\n 期望(容器.实例().状态.分钟).toEqual (25);\n 期望(容器.实例().状态.秒).toEqual (0);\n });\n
\n\n如果您运行测试,您将看到它们失败,因为我们还没有实现每个方法. 那么让我们实现每个函数来通过测试:
\n\n开始时间(){\n 这.设置状态({isOn: true});\n }\n\n stop计时器 () {\n 这.设置状态({关:假});\n }\n\n reset计时器 () {\n 这.stop计时器 ();\n 这.设置状态({\n 分钟:25日\n 秒:0,\n });\n}\n
\n\n如果运行测试,您将看到测试通过.\n现在,让我们实现剩下的函数 计时器.jsx:
\n\n从' 反应 '中导入反应, {Component};\n进口的./计时器.css ';\n导入计时器Button../ 计时器Button 计时器Button ';\n\n类定时器扩展组件{\n 构造函数(道具){\n 超级(道具);\n 这.状态= {\n 分钟:25日\n 秒:0,\n 关:假的,\n };\n\n 这.开始时间 = 这.开始时间.bind ();\n 这.stop计时器 =这个.stop计时器.bind ();\n 这.reset计时器 = 这.reset计时器.bind ();\n }\n\n 开始时间(){\n 如果(这.状态.isOn === true) {\n 返回;\n }\n 这.myInterval = setInterval(() => {\n Const{秒,分钟}=这个.状态;\n\n if (seconds > 0) {\n 这.setState(({ seconds }) => ({\n 秒:秒- 1;\n }));\n }\n If (seconds === 0) {\n If (minutes === 0) {\n clearInterval(这.myInterval);\n } else {\n 这.setState(({ minutes }) => ({\n 分钟:分钟- 1;\n 秒:59,\n }));\n }\n }\n }, 1000);\n 这.设置状态({isOn: true});\n }\n\n stop计时器 () {\n clearInterval(这.myInterval);\n 这.设置状态({关:假});\n }\n\n reset计时器 () {\n 这.stop计时器 ();\n 这.设置状态({\n 分钟:25日\n 秒:0,\n });\n }\n\n render = () => {\n Const {minutes, seconds} = 这.状态;\n\n 回报(\n \n \n {minutes}:{seconds < 10 ? ' 0${seconds} ': seconds}\n \n \n <计时器Button\n className=\"start-timer\"\n buttonAction ={这.开始时间}\n buttonValue ={'开始'}\n />\n <计时器Button\n className=\"stop-timer\"\n buttonAction ={这.stop计时器}\n buttonValue ={‘停止’}\n />\n <计时器Button\n className=\"reset-timer\"\n buttonAction ={这.reset计时器}\n buttonValue ={“重置”}\n />\n \n \n );\n };\n}\n\n导出默认定时器;\n
\n\n您将看到所有功能都是基于我们之前准备的用户描述工作的.
\n\n\n\n这就是我们如何使用TDD开发一个基本的反应应用程序. 如果用户描述和验收标准更详细, 可以更精确地编写测试用例, 从而贡献更多.
\n\n在使用TDD开发应用程序时, 不仅要将项目分解为史诗或用户故事,还要为验收标准做好准备,这一点非常重要. 在本文中, 我想向您展示如何分解项目,并为反应 TDD开发使用准备好的验收标准.
\n\n尽管有很多与反应 TDD相关的资源, 我希望这篇文章能够帮助您了解一些使用用户故事使用反应进行TDD开发的知识. 如果您选择模仿这种方法,请参考完整的源代码 在这里.
\n","as":"div","isContentFit":true,"sharingWidget":{"url":"http://yubz.toymonstertruck.com/react/tdd-react-user-stories-to-development","title":"Mastering 反应 Test-driven Development","text":null,"providers":["linkedin","推特","脸谱网"],"gaCategory":null,"domain":{"name":"developers","title":"工程","vertical":{"name":"developers","title":"开发人员","publicUrl":"http://yubz.toymonstertruck.com/developers"},"publicUrl":"http://yubz.toymonstertruck.com/developers/blog"},"hashtags":"反应,反应TDD,TDD"}} 365体育 皇冠博彩 森海塞尔官网 财客在线记账网 新葡京博彩 太阳城网址 威廉希尔亚洲 烟台交运集团网上售票平台 九牧官网 Buying-website-support@rvnetguy.com Top-ten-lottery-gambling-platforms-support@jinguangyuan.net 威廉希尔 bet365-Sports-support@u88xw.com 365bet体育 I-love-you-hr@whiest.com 奥特朗热水器官网 太阳城娱乐 身份证号大全 新葡京博彩官网 上海米腾实业有限公司 中国数据 青岛恒星科技学院 大麦资讯 中国知识产权网 dong10游戏 爱宠网 上海爱尔眼科医院 绿创环保 抚州人事考试网 达菲特 山东农业信息网 站点地图 佳美口腔 北京搜房网