咱们的首次测试html
让咱们来写首个测试。咱们首先须要使用shallowMount手动挂载咱们的组件,并将其存储在咱们将执行断言的变量中。咱们还能够经过propsData属性传递道具做为对象。vue
已安装的组件是一个对象,它有一些实用方法:程序员
而后,咱们能够写第一个断言:数组
让咱们来分析一下这里发生了什么。首先,咱们使用Jest的expect函数,它将咱们想要测试的值做为参数。在咱们的例子中,在父级上用findAll方法来获取具备活动类的全部元素。这将返回一个WrapperArray,包含Wrappers数组的对象。浏览器
一个WrapperArray有两个属性:父级(包含的Wrappers)和长度(Wrappers的数量)。后者是咱们须要拥有预期数量的stars。app
expect函数还返回一个对象,咱们能够在其上调用方法来测试传递的值。这些方法称为匹配器。在这里,咱们使用toEqual匹配器并将其做为参数传递给指望值。该方法返回一个布尔值(boolean),这是测试经过或失败的缘由。函数
总而言之,在这里,咱们指望在父级中找到的具备活动类的元素的总量应等于3(咱们分配给等级道具的值)。工具
在您的终端中,运行您的测试:单元测试
你应该看到它经过。 测试
模拟用户输入
Vue Test Utils能够轻松模拟真实用户最终在实际中所作的事情。在咱们的用例中,用户能够点击stars来切换它们。咱们能够在测试中使用触发器方法伪造它,并调度各类事件。
在这里,咱们首先用findAll获取第四颗star,它在传递的索引(从零开始的编号)中从WrapperArray返回一个Wrapper。而后,咱们模拟它上面的点击事件- 咱们模仿点击第四颗star的用户行为。
因为咱们将prop等级设置为3,所以在咱们点击以前,第四个star应该处于非活动状态,所以click事件应该使其处于活动状态。在咱们的代码中,这由一个活动类表示,咱们仅在它们被激活时附加在star上。咱们经过调用star上的classes方法来测试它,它将类名做为字符串数组返回。而后,咱们使用toContain匹配器来确保活动类在这里。
设置和拆解
因为咱们触发了对组件的点击,咱们已经改变了它的状态。问题是咱们在全部测试中使用相同的组件。若是咱们改变测试顺序并将其移到第一个位置会发生什么?而后第二次测试将失败。
在测试时,你不想依赖诸如命令这样的脆弱的东西。测试套件应该是强大的,而且除非您破坏API,不然理想状况下现有测试应该不会改变。
咱们但愿确保始终有一个可预测的父级来执行断言。咱们能够经过设置和拆卸功能实现这一目标。这能够帮助咱们在运行测试以前初始化,而后进行清理。
在咱们的例子中,有一种方法能够是在每次测试以前建立咱们的父级并在以后销毁它。
正如他们的名字所暗示的那样,beforeEach和afterEach分别在每次测试以前和以后运行。经过这种方式,咱们能够100%肯定每当咱们运行新测试时,咱们都能使用新的父级。
测试的特殊标识符
将选择器与样式和其余目的(例如测试钩子)混合毫不是一个好主意。
若是更改标签名称或类怎么办?
若是您在要测试的元素上没有特定的标识符,例如计数器,该怎么办?
您不想使用无用的类污染您的生产代码。为测试提供专用钩子会更好,例如专用数据属性,但仅限于测试期间。这样就不会在最终构建中留下一团糟。
处理此问题的一种方法是建立自定义Vue指令。
Vue.js实例有一个指令方法,它接受两个参数- 一个名称,以及在DOM中注入时组件生命周期的钩子函数。若是您不关心特定的钩子,也能够传递单个函数。
让咱们在src /中建立一个名为directives的新目录,并添加一个test.js文件。咱们将在咱们的指令中导出咱们想要传递的函数。
一个指令钩子能够带几个参数,在咱们的例子中,咱们只须要前两个:el和binding。el参数引用指令绑定的元素。binding参数是一个对象,它包含咱们在指令中传递的数据。这样咱们就能够按照本身的意愿操纵元素。
咱们将一个对象传递给咱们的指令,所以咱们能够从data-test-开始生成数据属性。在处理函数中,咱们绑定的每一个属性,并在元素上设置一个基于名称和值的数据属性。
咱们将一个对象传递给咱们的指令,所以咱们能够从data-test-开始生成数据属性。在处理函数中,咱们反复绑定每一个binding属性,并在元素上设置一个基于名称和值的数据属性。
如今咱们须要注册咱们的指令,以使用它。咱们能够在全球范围内进行,但在咱们的状况下,咱们只会在本地注册- 就在咱们的Rating.vue组件中。
咱们的指令如今能够在v-test名称下访问。尝试在计数器上设置如下指令:
如今使用开发人员工具检查浏览器中的HTML。你的面板应该是这样的:
开始工做了!如今,咱们在开发模式和构建项目时都不须要这个。此数据属性的惟一目的是可以在测试期间定位元素,所以咱们只想在运行它们时进行设置。为此,咱们可使用Webpack提供的NODE_ENV环境变量,这是为咱们的项目提供动力的模块捆绑器。
当咱们运行测试时,NODE_ENV被设置为'test'。所以,咱们可使用它来肯定什么时候设置测试属性。
在浏览器中刷新您的应用并再次检查计数器:数据属性已消失。
如今咱们能够对咱们须要定位的全部元素使用v-test指令。让咱们从前面开始测试:
咱们用[data-test-id =“star”]替换了.star选择器,它容许咱们在不破坏测试的状况下更改类以用于演示目的。这也是单一责任原则和松散耦合的好处之一 。
咱们是否还应该为咱们测试的类使用这些钩子?
在将此指令设置为要测试的目标元素以后,您可能想知道是否还应该使用它们来替换咱们主动查找的类。让咱们看看第一次测试的断言:
咱们应该对具备活动类的元素使用v-test,并在断言中替换选择器吗?好问题。
单元测试都是关于一次测试一件事。it函数的第一个参数是一个字符串,咱们用它来描述咱们从消费者的角度作的事情。
包装咱们断言的测试表示渲染一个类活动等于prop.grade的star列表。这是消费者的指望。当他们将数字传递给grade属性时,他们但愿得到相同数量的活跃或选定的star。然而,在咱们组件的逻辑中,活动类正是咱们用来定义这个特征的东西。咱们根据具体状况进行分配,所以咱们能够在视觉上区分活跃的stars。在这里,这个特定类的存在正是咱们想要测试的。
所以,在决定是否应该使用已有的选择器或设置v-test指令时,请问本身一个问题:我在测试什么,而且使用此选择器对业务逻辑透视图有意义吗?
它与功能或端到端测试有何不一样?
首先,单元测试组件可能看起来很奇怪。为何要对UI和用户交互进行单元测试?这不是功能测试吗?
在测试组件的公共API(也就是从消费者的角度来看)和从用户角度测试组件之间存在着根本但微妙的差别。首先,让咱们强调一些重要的东西:咱们正在测试定义良好的JavaScript函数,而不是UI。
当您查看单个文件组件时,很容易忘记组件编译成JavaScript函数。咱们没有测试底层的Vue机制,它从这个函数中致使了面向UI的反作用,好比在DOM中注入HTML。这就是Vue本身的测试已经解决的问题。在咱们的例子中,咱们的组件与任何其余函数没有区别:它接受输入并返回输出。这些缘由和后果是咱们正在测试的,而不是其余任何东西。
使人困惑的是,咱们的测试与常规单元测试略有不一样。一般,咱们写的东西以下:
这里没有争论。输入和输出数据,这就是咱们所关心的。对于组件,咱们指望呈现视觉的东西。咱们正在经过虚拟DOM并测试节点的存在。这也是您使用Selenium或Cypress.io等工具进行功能或端到端测试的方法。那有什么不一样呢?
经过单元测试,咱们正在测试单独的行为。经过功能或端到端测试,咱们正在测试场景。单元测试可确保程序单元的行为符合预期。它面向组件的消费者- 在软件中使用该组件的程序员。功能测试从用户角度确保功能或工做流的行为符合预期 。