莎拉·达扬 遵循 2019年5月17日 · 25分钟阅读< / div >< / div >< / div >< / div > 介绍与Vue.js测试驱动开发 图片由路易斯·里德在Unsplash 测试驱动的开发(TDD)是一个过程您编写测试,然后再编写相关代码。首先编写一个测试,描述一个预期行为,你运行它,确保它失败。然后,你写最愚蠢的,最简单的代码可以使测试通过。最后,您重构代码以使它正确。和你重复步骤为每个测试,直到你完成。 这种方法有很多优点。首先,它迫使你认为在你的代码。这是普遍急于编写代码之前建立它应该做什么。这种做法会导致浪费时间和编写复杂的代码。TDD,任何新代码需要先测试,所以你别无选择花时间来定义这段代码应该做什么再写。 其次,它确保你编写单元测试。从代码经常导致编写完整的测试,甚至根本没有测试。这种做法通常发生由于没有准确和详尽的规格,导致花费更多的时间比你应该编码。编写测试成为一个昂贵的努力,很容易破坏一旦生产代码已经准备好了。 构建健壮的代码单元测试是至关重要的。俯瞰或冲他们在生产中增加代码的机会打破。 为什么TDD组件? 测试一个组件可以是反直觉的。我们看到在你的第一个Vue单元测试。js组件,它需要一个心理转向充实你的大脑测试组件和测试简单的脚本,测试知道,了解单元测试和端到端之间的界线。 TDD使得这一切变得更加容易。而不是编写测试通过检查完成项目的所有片段,试图猜测你应该覆盖,你做的相反。你从实际规格,列表组件应该做的事情做,而不关心它。这种方式,你确保所有测试的公共API,但是你也保证你不要忘记任何东西。 在本教程中,我们将构建一个颜色选择器。对于每一个样本,用户可以访问匹配颜色代码,在十六进制,RGB或高速逻辑。 设计灵感来自自定义颜色选择器探索通过克里斯·卡斯蒂略 尽管它看似简单,但有很多小块的逻辑测试。他们跳进代码之前需要一些思考。 在本文中,我们将深入探究TDD。我们会把一些规格放在一起在我们编写一行代码。然后,我们将测试每一个公共功能测试驱动的方式。最后,我们将反思我们所做的看看我们能从中吸取教训。 在我们开始之前 本教程假设您已经与Vue创造出来的东西。js,编写单元测试使用Vue考试跑龙套和开玩笑(或类似的测试运行器)。它不会去深入的基本面,首先确保你赶上。如果你没有,我建议你去结束构建第一个Vue。js组件和你的第一个Vue单元测试。js组件。 TL;博士:这篇文章是如何以及为什么深入。这是旨在帮助您了解真实的Vue背后的每一个决定测试。js组件与TDD和教你如何让你的未来设计决策项目。如果你想了解整个思考过程,继续读下去。否则,你可以直接到追悔最后,还是看最后的代码GitHub。 写下你的规格 在编写你的第一个测试之前,你应该写下的概述组件应该做什么。有规格使测试更简单的因为你几乎重写每个规范形式的测试。 让我们考虑不同部分组成组件,和他们应该做什么。 首先,我们的集合颜色的色板。我们希望能够通过一个自定义颜色和显示列表的色板组件。第一个应该默认选中,最终用户可以选择一个新的通过点击它。 其次,我们有颜色模式善变者。最终用户应该能够在三种模式之间切换:十六进制(默认),RGB和高速逻辑。 最后,我们有颜色代码输出,最终用户可以得到当前选择的色卡的代码。这段代码是所选样本的组合和颜色模式。因此,默认情况下,它应该显示第一个样本作为一个十六进制值。这些变化时,代码应该相应地更新。 正如你所看到的,我们不要太深入细节;我们不指定颜色模式标签应该是什么,或活动状态的样子颜色色板。我们可以让大多数的小决定,即使做TDD。然而,我们来了从一个简单的定义组件应该是什么,从一组全面的规范。 编写测试驱动代码 首先,您需要创建一个新的Vue项目Vue CLI。你可以检查构建第一个Vue。js组件如果你需要一个循序渐进的指南。 在搭建过程中,手动选择功能,并确保你检查单元测试。选择笑话作为您的测试解决方案,并继续进行,直到项目被创建时,安装的依赖关系,你准备好了。 我们需要使用SVG文件作为组件,那么您还需要安装正确的加载程序。安装vue-svg-loaderdev依赖性,并添加一个规则在你的vue.config.js文件。 / / vue.config.js模块。出口= {chainWebpack:配置= > {const svgRule = config.module.rule (svg)svgRule.uses.clear ()svgRule.use (vue-svg-loader) .loader (“vue-svg-loader”)}} 这个装载机不讨好Jest默认情况下,将导致测试。修复它,创建一个svgTransform.js文件记录在网站上,编辑你的jest.config.js如下: / / svgTransform.jsconst vueJest =要求(“vue-jest / lib / template-compiler”)模块。出口= {过程(内容){const{呈现}= vueJest ({内容,attrs: {功能:假}})返回的模块。出口= {render: ${render} }`}}/ / jest.config.js模块。出口= {/ /……变换:{/ /……”。+ \ \。(css | styl少| | sass | scss | png | jpg | ttf woff | | woff2)美元”:“jest-transform-stub”,“^ + \ \。。svg美元':' < rootDir > / svgTransform.js '},/ /……} 请注意,我们将“svg”从第一个正则表达式(一个转换jest-transform-stub)。通过这种方式,我们确保svg被svgTransform.js。 此外,您需要安装color-convert作为一个依赖。我们需要在我们的代码和我们的测试。 还不为项目服务。我们要编写测试,依靠他们的传球还是不继续前进。我们不想控制是否我们构建的原理是在浏览器中测试它在视觉上,还是被如何看起来心烦意乱。 相反,打开您的项目,创建一个新的ColorPicker.vue一列纵队组件的src /组件/目录中。在测试/单位/,创建相关的规范文件。 < !- - -ColorPicker.vue- - ><模板>< div > < / div >< /模板><脚本>出口默认{}> < /脚本<时尚>> < /风格/ / ColorPicker.spec.js从“@vue / test-utils”进口{shallowMount}从“@ /组件/导入器选择器”描述(“选择器”,()= > {/ /让我们这样做吧!}) 在你的终端,执行以下命令运行测试: npm运行测试:单元——watchAll 现在,你应该得到一个错误,因为你还没有测试。不要担心;we’ll fix this shortly Note the usage of the——watchAll国旗在命令:笑话现在看你的文件。这样,您不需要手工重新运行测试。 TDD的三个阶段: 红色的:你编写一个测试,描述一个预期行为,然后运行它,确保它失败。李< / ><李id="63a6" class="ng nh iy km b kn np kr nq kv nr kz ns ld nt lh nl nm nn no ga">绿色:你写最愚蠢的,最简单的代码可以使测试通过。李< / ><李id="66e1" class="ng nh iy km b kn np kr nq kv nr kz ns ld nt lh nl nm nn no ga">重构:你重构代码以使它正确。李< / > 步骤1:红色 时间写我们的第一个测试!我们将从颜色色板。为了清晰起见,我们将把所有的测试为每个不同的元素在他们自己的套房,使用描述块。 首先,我们要确保组件显示每种颜色,我们提供作为一个个体样本。我们能通过这些道具,十六进制字符串数组的形式。在组件,我们将列表显示为一个无序列表,并分配通过一个背景颜色风格属性。 从“@vue / test-utils”进口{shallowMount}从“@ /组件/导入器选择器”从“color-convert”进口转换让包装=零const propsData = {色板:[‘e3342f’,‘3490年特区’,‘f6993f’,‘38 c172’,‘fff’)}beforeEach(() = >(包装= shallowMount(选择器,{propsData})))afterEach (() = > wrapper.destroy ())描述(“选择器”,()= > {描述(“色板”,()= > {测试(显示每种颜色作为一个个体的样布,()= > {const色板= wrapper.findAll (“.swatch”)propsData.swatches。forEach((斯沃琪、索引)= > {期望(swatches.at(指数).attributes () .style) .toBe (背景:rgb ($ {convert.hex.rgb(样本)。加入(" ")}))})})})}) 我们安装选择器组件和写了一个测试,希望找到物品与背景颜色匹配的颜色作为道具传递。这个测试是注定要失败的我们目前没有ColorPicker.vue。如果你看看你的终端,你应该有一个错误说不存在项目在0。这是伟大的!我们以优异的成绩通过TDD的第一步。 步骤2:绿色 我们的测试是失败的;我们在正确的轨道上。现在,时间让它通过。我们没有太多的兴趣编写工作或智能代码在这一点上,我们想要的是让Jest快乐。现在,Vue考试跑龙套抱怨我们不事件没有项目索引0。 [vue-test-utils]:不存在项目在0 最简单的事情我们可以做让错误消失是添加一个无序列表斯沃琪类的列表项。 <模板>< div class = "拾色" >< ul类=“色板”><李类= "斯沃琪" > < /李>< / ul >< / div >< /模板> 笑话仍然抱怨但是错误已经发生了变化: 预期值等于:背景:rgb(227, 52岁,47);“收到:未定义的 这是有道理的。列表项没有风格属性。最简单的事情我们可以做的是硬编码风格属性。这不是我们想要的最后,但是,我们并不担心。我们想要的是我们的测试去绿色。 因此我们可以硬编码五个列表项预期的样式属性: < ul类=“色板”><李类=“样本”风格= "背景:rgb(227年52岁,47);" > < /李><李类=“样本”风格= "背景:rgb(52、144、220); " > < /李><李类=“样本”风格= "背景:rgb(246、153、63); " > < /李><李类=“样本”风格= "背景:rgb(56、193、114); " > < /李><李类=“样本”风格= "背景:rgb(255、255、255); " > < /李>< / ul > 现在应该通过测试。 步骤3:重构 在这个阶段,我们要重新安排我们的代码,使它正确,而不破坏测试。在我们的例子中,我们不想让列表项和他们风格硬编码的属性。相反,它会更好收到色板作为一个道具,遍历生成列表项,指定的颜色作为背景。 <模板>< div class = "拾色" >< ul类=“色板”><李:关键= "指数”v代表= "(斯沃琪、索引)的色板”:风格= "{背景:“# ${斯沃琪}’}”类=“样本”李> < / >< / ul >< / div >< /模板><脚本>出口默认{道具:{色板:{类型:数组,默认(){返回[]}}}}> < /脚本 When tests re-run, they should still pass This means我们已经成功地重构代码不影响输出。恭喜你,你刚刚完成你的第一个TDD循环! 现在,在我们进入下一个测试,让我们反映。您可能想知道: “这是不是有点傻?我知道测试会失败。我不浪费时间,运行它,然后硬编码的值,测试通过,然后使代码对吗?我不能直接去重构一步?” 这是可以理解的,你感到困惑的过程。然而,试图从不同的角度看问题:这里的重点并不是证明测试不通过。我们知道它不会。我们想看看是什么我们的测试预计以最简单的方式让他们开心,最后编写智能代码而不会破坏任何东西。 测试驱动开发的整体思想:我们不写代码去做事,我们编写代码来让测试通过。通过逆转的关系,我们确保健壮的测试重点是结果。 我们测试的是什么? 另一个问题可能会介意我们如何决定哪些测试。在你的第一个Vue单元测试。js组件,我们看到,我们只能测试组件的公共API,而不是内部实现。严格地说,这意味着我们应该覆盖用户交互和道具的变化。 但是,所有的吗?例如,输出HTML打破吗?或CSS类名称改变?我们确定没有人依靠他们的吗?你不是你自己? 测试应该给你信心,你不航运破碎的软件。人们可以做什么和你的程序不应该停止工作他们期望的方式工作。这可能意味着不同的事情取决于项目和用例。 例如,如果您正在构建这种颜色面板作为一个开源组件,用户其他的开发人员在他们自己的项目中使用它。他们很可能依赖于您提供的类名来按自己的喜好风格组件。类名成为了一个公共API的一部分,因为用户依靠他们。 在我们的例子中,我们未必做一个开源组件,但我们有视图逻辑取决于特定的类名。例如,它的色板有一个重要的活跃活跃的类名,因为我们依赖它来显示一个标记,在CSS。如果有人改变这个意外,我们想了解它。 测试场景为UI组件高度依赖用例和期望。任何情况下,你需要问自己是什么如果它改变我关心这个吗? 下一个测试 测试样本 让我们继续下一个测试。我们预计第一斯沃琪列表的默认的选择。从外观看,这是我们想要确保继续以同样的方式工作。例如,用户可以依靠活跃的类名样式的组件。 测试(集第一个样本选择一个默认的,()= > {const firstSwatch = wrapper.find (“.swatch”)期望(firstSwatch.classes ()) .toContain(“活跃的”)}) 这个测试也应该会失败,列表项目目前没有任何类。我们可以很容易地使这个经过添加第一个列表项的类。 <李:关键= "指数”v代表= "(斯沃琪、索引)的色板”:风格= "{背景:“# ${斯沃琪}’}”类=“样本”:类= "{“活跃”:指数= = = 0}”李> < / > 现在测试通过;然而,我们硬编码到模板的逻辑。我们可以重构,通过外化的指数类应用。这种方式,我们可以改变它。 <模板>< !- - -。。。- - ><李:关键= "指数”v代表= "(斯沃琪、索引)的色板”:风格= "{背景:“# ${斯沃琪}’}”类=“样本”:类= "{活跃:指数= = = activeSwatch}”李> < / >< !- - -。。。- - >< /模板>出口默认{/ /……数据(){返回{activeSwatch: 0}}} 这自然使我们我们的第三个测试。我们想改变活动斯沃琪只要最终用户单击它。 测试(使斯沃琪活跃单击时,()= > {const targetSwatch = wrapper.findAll (.swatch)本(2)targetSwatch.trigger(点击)期望(targetSwatch.classes ()) .toContain(“活跃的”)}) 现在,当我们点击一个斯沃琪什么也没有发生。然而,由于我们之前的重构,我们可以做这个测试走向绿色,甚至跳过重构的步骤。 <李:关键= "指数”v代表= "(斯沃琪、索引)的色板”:风格= "{背景:“# ${斯沃琪}’}”类=“样本”:类= "{活跃:指数= = = activeSwatch}”@click = " activeSwatch =指数”李> < / > 这段代码使测试通过,甚至不需要重构。这是一个幸运的副作用做TDD:有时候,这个过程会导致编写新的测试,要么不需要重构,甚至通过。 活跃的色板应该显示选中标记。现在我们将添加不需要编写测试相反,我们会通过CSS后控制他们的可见性。这是好的,因为我们已经如何进行测试活跃的类应用。 首先,创建一个checkmark.svg文件中src /资产/。 < svg viewBox = " 0 0 448.8 448.8”><多边形点= " 0 142.8 323.9 35.7 216.8 252.5 142.8 395.3 448.8 89.3 413.1 53.6 " / >< / svg > 然后,导入组件。 从“@ /资产/ check.svg”进口CheckIcon出口默认{/ /……组件:{CheckIcon}} 最后,将它添加在列表项。 <李…>< check-icon / >李< / > 好!我们现在可以继续下一个元素的组件:颜色模式。 测试的颜色模式 现在让我们实现颜色模式善变者。最终用户应该能够在十六进制之间切换,RGB和高速逻辑。我们定义这些模式在内部,但我们希望确保他们正确呈现。 而不是测试按钮标签,我们会依赖类名。它使我们的测试更健壮,我们可以很容易地定义一个类名作为组件的合同的一部分。然而,应该能够更改按钮标签。 现在你可能会检查这三个特定的模式,但这将使测试脆性。如果我们改变他们呢?如果我们添加一个,或删除一个?仍然是同样的逻辑,然而,测试会失败,迫使我们去编辑它。 一个解决方案可以访问组件的数据迭代的动态模式。Vue考试跑龙套让我们通过虚拟机财产,但是,这种紧密耦合测试的内部实现模式。如果明天,我们决定改变我们定义模式的方式,测试将打破。 另一个解决方案是继续黑盒测试,只期望匹配给定的类名模式。我们不关心它color-mode-hex,color-mode-hsl或color-mode-xyz,只要它看起来像我们期望从外面。开玩笑让我们使用正则表达式匹配器。 / /……描述(颜色模型,()= > {测试(显示每个模式作为一个个体按钮,()= > {const按钮= wrapper.findAll (“.color-mode”)buttons.wrappers。forEach(按钮= > {期望(button.classes ()) .toEqual (expect.arrayContaining ([expect.stringMatching(/颜色模式- \ w {1,} /))))})})}) 这里,我们期待元素遵循这种模式的类“颜色模式——“+任何单词字符(ECMAScript的任何字符(a-zA-Z_0-9))。我们可以添加或删除任何我们想要的模式,和测试仍然是有效的。 当然,现在,测试应该会失败,因为没有按钮类颜色模式然而。我们可以让它通过硬编码这些组件。 < div class = "模式" ><按钮类= "颜色模式color-mode-hex " > < /按钮><按钮类= "颜色模式color-mode-rgb " > < /按钮><按钮类= "颜色模式color-mode-hsl " > < /按钮>< / div > 我们现在可以重构代码通过添加模式作为私有数据在我们的组件和遍历。 <模板>< !- - -。。。- - >< div class = "模式" ><按钮:关键= "指数”v代表= " colorModes模式下,指数”类= "颜色模式":类= "颜色模式- ${模式}”> >{{模式}}< /按钮< / div >< !- - -。。。- - >< /模板>出口默认{/ /……数据(){返回{activeSwatch: 0,colorModes:(“六角”、“rgb”,“高速逻辑”)}}} 好!让我们继续。 与色板一样,我们希望第一个模式设置为活跃。我们可以复制测试我们写和适应这个新的用例。 测试(“集第一模式选择一个默认的,()= > {const firstButton = wrapper.find (“.color-mode”)期望(firstButton.classes ()) .toContain(“活跃的”)}) 我们可以做这个测试通过手动添加第一个列表项的类。 <按钮:关键= "指数”v代表= " colorModes模式下,指数”类= "颜色模式":类= "[{活跃:指数= = = 0},颜色模式- ${模式}']”> >{{模式}}< /按钮 最后,我们可以通过外部化重构索引到这类应用。 <模板>< !- - -。。。- - ><按钮:关键= "指数”v代表= " colorModes模式下,指数”类= "颜色模式":类= "[{活跃:指数= = = activeMode},颜色模式- ${模式}']”> >{{模式}}< /按钮< !- - -。。。- - >< /模板>出口默认{/ /……数据(){返回{activeSwatch: 0,activeMode: 0,colorModes:(“六角”、“rgb”,“高速逻辑”)}}} 我们需要改变活动方式只要最终用户点击相关按钮,与色板。 测试(“设置颜色模式按钮时主动点击的,()= > {const targetButton = wrapper.findAll (.color-mode)本(2)targetButton.trigger(点击)期望(targetButton.classes ()) .toContain(“活跃的”)}) 现在我们可以添加一个@click指示我们的色板,使测试走向绿色无需重构。 <按钮:关键= "指数”v代表= " colorModes模式下,指数”类= "颜色模式":类= "[{活跃:指数= = = activeMode},颜色模式- ${模式}']”@click = " activeMode =指数”> >{{模式}}< /按钮 测试的颜色代码 现在,我们完成了测试样本和颜色代码,我们可以继续我们的第三个和最后一个元素颜色选择器:颜色代码。我们显示的是另外两个的组合:所选样本定义我们应该显示的颜色,和选择的模式决定了如何显示它。 首先,我们要确保我们最初显示默认的斯沃琪在默认模式。我们有信息来构建这个自从我们色板和颜色模式实现。 让我们先从一个(失败)测试。 描述(颜色代码,()= > {测试(在默认模式中显示默认样本的,()= > {期望(wrapper.find (.color-code)。text ()) .toEqual (“# e3342f”)})}) 现在,让我们把这个通过硬编码在组件预期的结果。 < div class = "经过" > # e3342f < / div > 好!重构的时候了。我们有一个原始的十六进制颜色模式,我们愿意输出十六进制格式。我们的输入和输出值的唯一区别是,我们想要预先考虑后者一个散列的性格。Vue这样做的简单的方法是通过一个计算财产。 <模板>< !- - -。。。- - >< div class = "经过" > {{activeCode}} < / div >< !- - -。。。- - >< /模板>出口默认{/ /……计算:{activeCode () {返回“# $ {this.swatches [this.activeSwatch]}”}}} 这应该保持测试绿色。然而,有一个问题这个计算属性:它只适合十六进制值。它应该继续工作,当我们改变颜色,但当我们改变模式。我们可以确认这个和另一个测试。 测试(“代码显示在正确的模式改变模式”时,()= > {wrapper.find (.color-mode-hsl) .trigger(点击)期望(wrapper.find (.color-code)。text ())。toEqual (2°, 76%, 54%)}) 在这里,我们已经改变了高速逻辑模式,但我们仍然十六进制输出。因此我们我们需要重构代码activeCode计算属性不仅意识到当前的颜色,而且当前的颜色模式。我们可以实现这一目标的方法之一是创建计算属性为每个模式和代理他们通过activeCode基于所选择的模式。 首先,我们应该简化访问当前的颜色和模式。现在,我们需要做一个数组中查找,重复,使代码难以阅读。我们可以使用计算属性来包装这个逻辑。 出口默认{/ /……计算:{/ /……activeColorValue () {返回this.swatches [this.activeSwatch]},activeModeValue () {返回this.colorModes [this.activeMode]}}} 正如你所看到的,我们不为这些计算属性编写测试,因为他们不是我们的公共API的一部分。以后我们将使用它们在我们的专用颜色模式计算属性,它自己将代理activeCode,我们在“颜色代码”测试套件。我们关心的是,呈现的颜色代码所以用户可以依靠他们。有我们得到了实现细节,我们需要能够改变如果需要。 我们现在可以写我们的专用计算属性为每个模式。我们将他们的名字上的地图colorModes,所以我们可以稍后查找数组activeCode返回正确的。 十六进制输出,我们可以外部化我们目前所拥有的activeCode和重构使用activeColorValue。 出口默认{/ /……计算:{/ /……十六进制(){返回“# $ {this.activeColorValue} '}}} 现在,让我们来修改activeCode所以代理正确的计算属性取决于主动模式。 出口默认{/ /……计算:{/ /……activeCode () {返回这个[this.activeModeValue]}}} 这还不应该使我们的最新测试通过,因为我们还没有写一个计算的属性。然而,我们的测试,检查是否默认模式呈现正确还是传球,这是一个好迹象,我们在正确的轨道上。 我们现在想写一个计算的属性返回颜色输出高速逻辑模式。在这个例子中,我们使用color-convertnpm包,让我们在许多不同的模式转换颜色。我们已经使用它在我们的测试中,所以我们不需要重新安装它。 从“color-convert”进口转换出口默认{/ /……计算:{/ /……奥软(){const hslColor = convert.hex.hsl (this.activeColorValue)返回“$ {hslColor [0]}°, $ {hslColor [1]} %, $ {hslColor [2]} %’}}} 太好了,我们的测试通过!我们现在可以完成这个添加缺失的RGB模式。 然而,正如您所看到的,我们目前没有测试的输出颜色单独计算属性,而是通过其他的测试。为了让事情更清洁,我们可以解耦的逻辑组件,进口的依赖,并分别对其进行测试。这有几个好处: 它使组件从种植每次我们想添加一个颜色模式,李< / ><李id="518b" class="ng nh iy km b kn np kr nq kv nr kz ns ld nt lh on nm nn no ga">它使域分离:组件关注自己的视图逻辑,和颜色模式详尽实用程序负责测试每个模式。李< / >< / ul >首先,创建一个新的color.js文件src /跑龙套目录,和一个匹配的规范文件测试/单位/。 / / color.spec.js从“进口{rgb,十六进制,奥软}@ /跑龙套/颜色的/ / color.js从“color-convert”进口转换出口const rgb = () = > {}出口const十六进制= ()= > {}出口const奥软= ()= > {} 我们可以使用TDD测试这三个功能,并确保他们总是返回预期的值。我们可以提取逻辑在Vue最后两个组件,并编写从头RGB函数。 为了简便起见,我们将讨论这三个测试,但是这个过程是相同的。 从“进口{rgb,十六进制,奥软}@ /跑龙套/颜色的const颜色= ' e3342f '描述(“颜色”,()= > {测试(“返回到RGB颜色符号”,()= > {期望(rgb(颜色)。托比(227年52岁,47)})测试(返回颜色成十六进制符号,()= > {期望(十六进制(颜色)).toBe (“# e3342f”)})测试(“返回到高速逻辑符号的颜色,()= > {期望(奥软(颜色))。托比(2°,76%,54%)})}) 我们现在有三个测试失败。我们能做的第一件事就是返回去绿色的硬编码的值。 出口const rgb =() = > ' 227, 52岁,47岁的出口const十六进制= ()= > ' # e3342f '出口const奥软=()= > 2°,76%、54%的 现在,我们可以开始重构迁移Vue组件的代码。 出口const十六进制=()= > ' # ${颜色}'出口const奥软= = >{颜色const hslColor = convert.hex.hsl(颜色)返回“$ {hslColor [0]}°, $ {hslColor [1]} %, $ {hslColor [2]} %’} 最后,我们可以实现rgb函数。 出口const rgb颜色= = > convert.hex.rgb(颜色)。加入(" ") 所有测试都应该保持绿色! 我们现在可以使用颜色公用事业在我们Vue组件和重构它。我们不再需要进口color-convert在组件,也不需要专门的计算属性为每个模式,甚至获得活跃的颜色和模式值。我们需要保持activeCode,我们可以存储所有必要的逻辑。 这是一个很好的例子,做黑盒测试可以帮助我们:我们一直专注于测试的公共API;因此我们可以重构的内部组件在不破坏测试。删除属性如activeColorValue或十六进制没关系,因为我们从未直接测试。 / /……从“进口{rgb,十六进制,奥软}@ /跑龙套/颜色的const模式= {rgb,十六进制,奥软}出口默认{/ /……计算:{activeCode () {const activeColor = this.swatches [this.activeSwatch]const activeMode = this.colorModes [this.activeMode]返回模式[activeMode] (activeColor)}}} 我们现在有很多要简洁代码组件,和更好的域分离,同时尊重组件的合同。 最后,我们可以实现一个失踪的测试:确保颜色的代码更改当我们点击一个新样本。这应该已经走向绿色,但它仍然是必不可少的我们写它,所以我们可以知道如果它打破。 测试('显示正确的颜色时改变颜色的代码,()= > {包装器.findAll (“.swatch”)本(2).trigger(点击)期望(wrapper.find (.color-code)。text ()) .toEqual (“# f6993f”)}) 我们完成了!我们刚刚建立了一个功能齐全的Vue组件使用TDD,不依赖浏览器输出,和我们的测试做好准备。 目视管理 现在我们的组件已经准备好了,我们可以看到它在浏览器中看起来和玩。这允许我们添加CSS和确保我们没有错过任何东西。 首先,挂载到主要的组件App.vue文件。 < !- - -App.vue- - ><模板>< div id =“应用程序”><拾色:色板= " [‘e3342f’,‘3490年特区’,‘f6993f’,‘38 c172’,‘fff’) " / >< / div >< /模板><脚本>从“@ /组件/导入器选择器”出口默认{名称:“应用程序”,组件:{选择器}}> < /脚本 然后,运行应用程序通过执行以下脚本,并在浏览器中打开它http://localhost: 8080 /。 npm运行服务 您应该看到你的颜色选择器!它看起来不像,但它的工作原理。试着点击颜色和改变颜色模式;您应该看到颜色代码更改。 组件通过适当的样式,添加以下CSS之间风格标签: .color-picker {background - color: # fff;边界:1 px固体# dae4e9;border - radius: 0.125快速眼动;不必:0 2 px 4 px 0 rgba (0, 0, 0, 0.1);颜色:# 596 a73;无衬线字体类型:BlinkMacSystemFont, Helvetica Neue;填充:1快速眼动;}.swatches {颜色:# fff;显示:flex;flex-wrap:包装;list-style:没有;利润:-0.25雷姆-0.25雷姆0.75快速眼动;填充:0;}.swatch {border - radius: 0.125快速眼动;光标:指针;高度:2快速眼动;利润:0.25快速眼动;位置:相对;宽:2快速眼动;}{后.swatch::border - radius: 0.125快速眼动;底部:0;不必:插图0 0 0 1 px # dae4e9;内容:”;显示:块;左:0;mix-blend-mode:繁殖;位置:绝对的;右:0;上图:0;}.swatch svg {显示:没有;颜色:# fff;填充:currentColor;利润:0.5快速眼动;}.swatch。活跃的svg {显示:块;}.color-modes {显示:flex;字体大小:1快速眼动;字母间距:0.05快速眼动;保证金:0 -0.25雷姆0.75快速眼动;}.color-mode {背景:无;边界:没有;颜色:# 9 babb4;光标:指针;显示:块;粗细:700;保证金:0 0.25快速眼动;填充:0;首字母:大写;}.color-mode。活跃的{颜色:# 364349;}.color-code {边界:1 px固体# dae4e9;border - radius: 0.125快速眼动;颜色:# 364349;首字母:大写;填充:0.75快速眼动;} 您应当会看到类似这样的: 我们完成了! 追悔 我们怎样才能改善呢? 现在,我们有一个健壮的测试套件。即使我们没有100%的覆盖率,我们可以用我们的组件有信心出去在野生环境中,随着时间的推移和发展。仍然有几件事情我们可以改善,根据用例。 首先,你可能会注意到,当单击白色斯沃琪,选中标记不出现。这不是一个错误,而视觉问题:选择目录,但我们看不见它,因为它是白色的白色。你可以添加一些逻辑来解决这个问题:当一个颜色是轻于某个阈值(比方说90%),你可以添加一个光类样本。这将让您应用一些特定CSS和黑暗的选中标记。 幸运的是,你已经拥有你所需要的:color-converter包可以帮助您确定是否一个颜色是光(奥软工具),你已经有一个颜色实用程序和测试模块存储逻辑隔离。看到完成的代码可能会是什么样子,看看项目的存储库GitHub。 我们还可以加强套件通过添加一些测试以确保一些预期的类。这并不实际测试逻辑,但仍会特别有用如果有人依靠这些类名风格从外部组件。再一次,一切都取决于你的用例:测试什么不应该改变你不知情的情况下,不只是增加测试为了它。 我们学习了什么? 有几个课程学习这TDD实验。它带来了很多表,但也强调了一些挑战,我们应该意识到。 首先,TDD是a神奇的方式编写健壮的测试,不是太多,而不是太少。你有没有完成一个组件,转移到测试和想法吗“我甚至从哪里开始?”吗?看完代码并找出测试是困难的。人们很容易迅速完成,忽略一些关键部分和最后一个不完整的测试套件。或者你可以采取防御的方法,测试一切,冒着专注于实现细节和写作脆性测试。 采用TDD开发UI组件帮助我们关注什么测试通过定义,在编写任何代码之前,如果这是合同的一部分。 其次,TDD鼓励重构,导致更好的软件设计。当你编写测试代码后,你通常不在一个重构的动态。你可以修复您的代码在测试时如果你发现问题,但是在这个阶段,你最有可能完成实现。这种分离写代码和编写测试之间,存在着问题。 TDD,你创建一个更深层次的代码和测试之间的联系,并重点公共API的可靠。实现是正确的在你保证结果。这就是为什么绿色步骤是至关重要的:首先需要你的测试通过,然后确保它永远不会休息。实现你的工作解决方案,而是你逆转的关系,首先关注合同,并允许实现一次性。因为重构,最后和你建立了合同,你现在有心理空间使事情对的,干净的一些代码,采用更好的设计,或专注于性能。 值得注意的是TDD和规格更容易跟随。当你已经有一个清晰的了解组件应该做的一切,你可以将这些规范转化为测试。有些团队使用这样的框架ATDD(验收测试驱动开发),涉及各方从业务的角度规范发展。最终的规格,或验收测试,是一个完美的基础来编写测试遵循TDD。 另一方面,使用TDD测试UI组件是很困难的,和需要一些先验知识之前。首先,你需要了解您的测试库这样你可以编写可靠的断言。看看测试我们写了一个正则表达式:语法不是最直接的。如果你不知道图书馆,很容易编写一个测试失败的原因,最终将阻碍整个测试驱动开发过程。 同样,你需要注意的一些细节关于你期望的值;否则,你最终可能会与您的测试和做一些恼人的回复。上,UI组件比renderless库更具挑战性,因为各种方法可以实现DOM规范。 以我们的第一个测试套件为例:我们测试的背景颜色。然而,尽管我们通过十六进制颜色,我们预计RGB返回值。这是因为Jest用途jsdom,一个节点。js DOM和HTML标准的实现。如果我们运行我们的测试在一个特定的浏览器,我们可能有不同的返回值。这可能会非常棘手,当你测试不同的引擎。您可能会寻求一些更高级的转换实用程序或使用环境变量来处理各种实现。 值得吗? 如果你做到这一步,你可能已经意识到这一点TDD的要求时间。这篇文章本身是在6000字!这可有点吓人的如果你习惯更快的开发周期,而且可能看起来是不可能的,如果你经常在压力下工作。然而,重要的是要破灭的神话,TDD双开发时间小的投资回报,因为这是完全错误的。 TDD需要一些实践,随着时间的推移,你会得到更快。今天感觉笨拙的明天可以成为第二天性,如果你经常这样做。我鼓励你不要丢弃的东西,因为它是新的和感觉尴尬:给它一些时间来评估它相当,然后做出决策。 其次,时间花在编写测试驱动代码是你不会花修复bug。 修复bug更昂贵的比阻止他们。如果你曾经不得不修复关键生产错误,你知道这个感觉接近持有一个开放的伤口在外科病人用一只手,同时试图与另一个操作。在沙漠里。在晚上。瑞士军刀。混乱的,压力,理想,和熊高糟蹋东西的机会。如果你想保持你的理智和信任你的最终用户在您的软件,你想要不惜一切代价避免这些情况。 测试帮助你发现错误然后才进入生产,和TDD可以帮助你写出更好的测试。如果你认为你应该测试软件,那么你应该关心这些测试有用的在第一时间。否则,整件事只是浪费时间。 与什么一样,我鼓励你去尝试TDD丢弃之前的想法。如果你一直遇到的生产问题,或者你认为你可以提高你的开发过程,然后值得给它一枪。有限的一段时间试试,测量的影响,并比较结果。你可能会发现一个方法,可以帮助你更好的软件,和感觉更自信的“配置”按钮。 从我们搬到了freeCodeCamp.org/news 我们已经搬到https://freecodecamp.org/news,每周发布大量的教程。看到你在那里。 阅读更多的< !- - -- - >我们已经搬到freeCodeCamp.org/news 建议从媒介betway娱乐官网 Strapi 如何构建一个简单的CRUD应用程序使用颤振和Strapi吗< / div > 马克斯·拉姆齐 如何轻松地发送通过人不和的消息吗< / div > 约西亚Ilesanmi 思考与JavaScript不变性< / div > Ashok Maharjan 常见的JavaScript数组方法< / div > 埃里克•艾略特 在 JavaScript的场景 JavaScript的两大支柱< / div > Stav Alfi 在 octopol-engineering 生产和消费与卡夫卡(多)< / div > Yahya Jamaldine 在 JavaScript用浅显的英语 9 JavaScript概念之前你应该知道学习的反应< / div > Karthick Ragavendran 先进回来的片和重新选择和异步铛。< / div > 关于帮助条款隐私 得到了媒介的应用betway娱乐官网 开始 莎拉·达扬 834的粉丝 前端开发人员与设计和排版。我喜欢分享我所知道的HTML、CSS和JavaScript, UI / UX和其他东西。 遵循 帮助 状态 作家 博客 职业生涯 隐私 条款 关于 可知