如何对第一个Vue.js组件进行单元测试

by Sarah Dayan

通过莎拉·达扬

In Build Your First Vue.js Component we made a star rating component. We’ve covered many fundamental concepts to help you create more complex Vue.js components.

在“ 构建您的第一个Vue.js组件”中,我们制作了星级评分组件。 我们介绍了许多基本概念,以帮助您创建更复杂的Vue.js组件。

Yet, there’s one crucial point you need to build bulletproof components you can use in production: unit testing.

但是,构建可在生产中使用的防弹组件的关键一点是: 单元测试

为什么要对组件进行单元测试? (Why unit test a component?)

Unit tests are a crucial part of continuous integration. They make your code a lot more reliable by focusing on small, isolated entities and making sure these always behave as expected. You can confidently iterate on your project without fear of breaking things.

单元测试是持续集成的关键部分。 通过专注于小的孤立实体并确保它们始终表现出预期的行为,它们使您的代码更加可靠。 您可以放心地在您的项目上进行迭代,而不必担心会遇到麻烦。

Unit tests aren’t limited to scripts. Anything we can test in isolation is unit testable, as long as you respect a few good practices. These practices include single-responsibility, predictability, and loose coupling.

单元测试不仅限于脚本。 只要您尊重一些良好做法,我们可以单独测试的所有内容都是可以单元测试的。 这些实践包括单一职责,可预测性和松散耦合。

As reusable entities of our app, Vue.js components are great candidates for unit testing. We’ll test the one we made as a single unit with various inputs and user interactions, and make sure it always behaves as we expect.

作为我们应用程序的可重用实体, Vue.js组件非常适合进行单元测试 。 我们将测试具有多个输入和用户交互的单个单元,并确保其始终像我们期望的那样运行。

开始之前 (Before we start)

A few things have changed since the initial tutorial. Vue CLI 3 was released. Vue Test Utils — the official Vue.js unit testing utility library — has matured to beta version. In the first tutorial, we used webpack-simple, a prototyping template that doesn’t include testing features. For these reasons, the simplest thing to do is to wipe the slate clean and migrate the project from the tutorial to a more recent Vue.js install.

自从最初的教程以来,发生了一些变化。 Vue CLI 3已发布。 Vue Test Utils —官方的Vue.js单元测试实用程序库—已成熟到beta版。 在第一个教程中,我们使用了webpack-simple ,这是一个不包含测试功能的原型模板。 由于这些原因,最简单的方法是清除所有内容并将项目从教程迁移到最新的Vue.js安装。

I re-created the project from the first tutorial so you can download it directly from GitHub. Then, navigate to the unzipped directory and install dependencies.

我从第一个教程中重新创建了该项目,因此您可以直接从GitHub下载它。 然后,导航到解压缩目录并安装依赖项。

Note: make sure you install Node.js before going further:

注意:在继续操作之前, 确保安装Node.js :

cd path/to/my/project npm install

Then, run the project:

然后,运行项目:

npm run serve

Vue测试实用程序和笑话 (Vue Test Utils and Jest)

For this tutorial, we’ll use Vue Test Utils, the official Vue.js testing toolkit, along with Jest, a JavaScript test runner backed by Facebook.

在本教程中,我们将使用Vue Test Utils (官方Vue.js测试工具包)以及Jest (由Facebook支持JavaScript测试运行程序)一起使用。

Vue Test Utils lets you mount Vue components in isolation and simulate user interactions. It has all the necessary utilities to test single-file components, including those using Vue Router or Vuex.

Vue Test Utils可让您隔离安装Vue组件并模拟用户交互。 它具有测试单文件组件的所有必需实用程序,包括使用Vue Router或Vuex的组件。

Jest is a full-featured test runner that requires almost no configuration. It also provides a built-in assertion library.

Jest是功能齐全的测试运行程序,几乎不需要配置。 它还提供了一个内置的断言库。

Vue CLI 3 (which I used to generate the boilerplate) allows you to pick your favorite test runner, and sets it up for you. If you want to use another test runner (like Mocha), install Vue CLI 3 and generate your own starter project. Then you can migrate the source files from my boilerplate right in it.

Vue CLI 3(我用来生成样板 )使您可以选择自己喜欢的测试运行器,并为您进行设置。 如果要使用其他测试运行程序(例如Mocha ),请安装Vue CLI 3并生成您自己的启动程序项目。 然后,您可以在其中直接从样板迁移源文件。

我们应该测试什么? (What should we test?)

A common approach of unit testing is to only focus on the public API (aka black box testing). By overlooking implementation details, you’re allowing internals to change without having to adapt tests. After all, what you want to do is make sure your public API won’t break. What happens under the hood is indirectly tested, but all that matters is for the public API to remain reliable.

单元测试的常见方法是仅关注公共API (又名黑盒测试)。 通过忽略实施细节,您无需更改测试即可允许内部更改。 毕竟,您要做的就是确保您的公共API不会损坏 。 幕后发生的事情经过间接测试,但重要的是公共API保持可靠。

This is also the official recommendation from the Vue Test Utils guides. Therefore, we’ll only test what we can access from the outside of the component:

这也是Vue Test Utils指南中的官方建议。 因此,我们仅测试可以从组件外部访问的内容:

  • user interactions

    用户互动
  • props changes

    道具变更

We won’t directly test computed properties, methods, or hooks. These will be implicitly tested by testing the public interface.

我们不会直接测试计算的属性,方法或挂钩。 这些将通过测试公共接口进行隐式测试。

设置规格文件 (Setting up a spec file)

Like with regular tests, each component has a spec file which describes all tests we want to run.

与常规测试一样,每个组件都有一个规范文件,该文件描述了我们要运行的所有测试。

Specs are JavaScript files. By convention, they have the same name as the components they’re testing, plus a .spec suffix.

规范是JavaScript文件。 按照惯例,它们与要测试的组件同名,并带有.spec后缀。

Go ahead and create a test/unit/Rating.spec.js file:

继续创建一个test/unit/Rating.spec.js文件:

// Rating.spec.js
import { shallowMount } from '@vue/test-utils'import Rating from '@/components/Rating'
describe('Rating', () => {  // your tests go here})

We’ve imported our Rating component and shallowMount. The latter is a Vue Test Utils function which lets us mount our component without mounting its children.

我们已经导入了我们的Rating组件和shallowMount 。 后者是Vue Test Utils函数,它使我们可以在不安装子组件的情况下安装组件。

The describe function call wraps all the test we’re about to write — it describes our testing suite. It has its own scope, and can itself wrap other nested suites.

describe函数调用包装了我们将要编写的所有测试,它描述了我们的测试套件 。 它具有自己的作用域,并且本身可以包装其他嵌套套件。

Enough said, let’s start writing tests.

够了, 让我们开始编写测试

确定测试方案 (Identifying testing scenarios)

When we look at Rating from the outside, we can see it does the following:

当我们从外部查看Rating ,我们可以看到它执行以下操作:

  • it renders a list of stars which is equal to the value of the maxStars prop the user passes

    它呈现一个与用户通过的maxStars值相等的星星列表

  • it adds an active class to each star whose index is lower than or equal to the stars prop the user passes

    它为索引小于或等于用户通过的stars每个星星添加一个active

  • it toggles the active class on a star when the user clicks it and removes it on the next stars

    当用户单击某个active类别时,它将在该active类别上切换,然后在下一个active类别中将其删除

  • it toggles the icons star and star-o when the user clicks a star

    当用户单击星号时,它将在starstar-o切换

  • it renders a counter if the user sets the hasCounter prop to true, hides it if they set it to false, and displays text saying how many stars of the maximum number of stars are currently active.

    如果用户将hasCounter prop设置为true ,则将呈现一个计数器;如果将hasCounter prop设置为false ,则将隐藏该计数器;并显示文本,说明当前处于活动状态的最大星数中的几颗。

Notice we’re only looking at what the component does from the outside. We don’t care that clicking a star executes the rate method, or that the internal stars data property changes. We could rename these, but this shouldn’t break our tests.

注意,我们只是从外部查看组件的功能。 我们不在乎单击星标执行rate方法,还是在内部stars数据属性更改。 我们可以重命名它们,但这不会破坏我们的测试。

我们的第一个测试 (Our first test)

Let’s write our first test. We first need to manually mount our component with shallowMount, and store it in a variable on which we’ll perform assertions. We can also pass props through the propsData attribute, as an object.

让我们写我们的第一个测试。 首先,我们需要使用shallowMount手动安装组件,并将其存储在将要执行断言的变量中。 我们还可以将props作为对象通过propsData属性传递。

The mounted component is an object which comes with a handful of useful utility methods:

挂载的组件是一个对象,带有一些有用的实用程序方法:

describe('Rating', () => {  const wrapper = shallowMount(Rating, {    propsData: {      maxStars: 6,      grade: 3    }  })  it('renders a list of stars with class `active` equal to prop.grade', () => {    // our assertion goes here  })})

Then, we can write our first assertion:

然后,我们可以编写第一个断言:

it('renders a list of stars with class `active` equal to prop.grade', () => {  expect(wrapper.findAll('.active').length).toEqual(3)})

Let’s analyze what’s happening here. First, we’re using Jest’s expect function, which takes the value we want to test as an argument. In our case, we call the findAll method on our wrapper to fetch all elements with an active class. This returns a WrapperArray, which is an object that contains an array of Wrappers.

让我们分析一下这里发生的事情。 首先,我们使用玩笑的expect功能,这需要我们想要的值来测试作为参数。 在我们的例子中,我们在wrapper上调用findAll方法来获取具有active类的所有元素。 这将返回WrapperArray ,该对象是包含Wrappers数组的对象。

A WrapperArray has two properties: wrappers (the contained Wrappers) and length (the number of Wrappers). The latter is what we need to have the expected number of stars.

WrapperArray具有两个属性: wrappers (所包含的Wrappers )和length (的数量Wrappers )。 后者是我们需要具有预期星数的东西。

The expect function also returns an object on which we can call methods to test the passed value. These methods are called matchers. Here, we use the toEqual matcher and pass it the expected value as in arguments. The method returns a boolean, which is what a test expects to either pass or fail.

expect函数还返回一个对象,我们可以在该对象上调用方法以测试传递的值。 这些方法称为匹配器 。 在这里,我们使用toEqual匹配器并将期望的值传递给参数。 该方法返回一个布尔值,这是测试期望通过或失败的布尔值。

To summarize, here we say we expect the total amount of elements with the class active we find in our wrapper to be equal to 3 (the value we assigned to the grade prop).

总而言之,在这里我们说我们期望在包装器中找到的active类的元素总数等于3(我们为grade道具分配的值)。

In your terminal, run your test:

在终端中,运行测试:

npm run test:unit

You should see it pass ?

您应该看到它通过吗?

Time to write some more.

是时候写更多了。

模拟用户输入 (Simulating user input)

Vue Test Utils makes it easy to simulate what real users end up doing in production. In our case, users can click on stars to toggle them. We can fake this in our tests with the trigger method, and dispatch all kinds of events.

Vue Test Utils使模拟真实用户最终在生产中所做的工作变得容易。 在我们的情况下,用户可以单击星号来切换它们。 我们可以使用trigger方法在测试中进行伪造,并调度各种事件。

it('adds `active` class on an inactive star when the user clicks it', () => {  const fourthStar = wrapper.findAll('.star').at(3)  fourthStar.trigger('click')  expect(fourthStar.classes()).toContain('active')})

Here, we first get our fourth star with findAll and at, which returns a Wrapper from a WrapperArray at the passed index (zero-based numbering). Then, we simulate the click event on it — we’re mimicking the action from a user who would click or tap the fourth star.

在这里,我们首先使用findAllat获得第四颗星,它从WrapperArray返回传入的索引(从零开始的编号)处的Wrapper 。 然后,我们模拟其上的click事件-我们模仿的是单击或轻击第四颗星星的用户的操作。

Since we set the grade prop to 3, the fourth star should be inactive before we click, therefore the click event should make it active. In our code, this is represented by a class active which we append on stars only when they’re activated. We test it by calling the classes method on the star, which returns its class names as an array of strings. Then, we use the toContain matcher to make sure the active class is here.

由于我们将grade prop设置为3,因此在单击之前第四颗星星应该处于非活动状态,因此单击事件应使其处于活动状态。 在我们的代码中,这由active类表示,仅当激活它们时,我们才将它们附加在星星上。 我们通过在星号上调用classes方法来对其进行测试,该方法将其类名称作为字符串数组返回。 然后,我们使用toContain匹配器确保active类在此处。

设置和拆卸 (Setup and teardown)

Since we’ve triggered a click on our component, we’ve mutated its state. The problem is that we’re using that same component for all our tests. What happens if we change the order of our tests, and move this one to first position? Then the second test would fail.

由于我们触发了组件的点击,因此我们改变了它的状态。 问题是我们在所有测试中都使用了相同的组件。 如果我们更改测试顺序并将其移至第一位会发生什么? 然后第二次测试将失败。

You don’t want to rely on brittle things like order when it comes to tests. A test suite should be robust, and existing tests should ideally not change unless you’re breaking the API.

在测试中,您不想依赖诸如订单之类的易碎物品。 测试套件应该很健壮,并且理想情况下,除非破坏API,否则现有测试不应更改。

We want to make sure we always have a predictable wrapper to perform assertions on. We can achieve this with setup and teardown functions. These are helpers which let us initialize things before we run tests, and clean up afterward.

我们要确保始终有一个可预测的包装器来执行断言。 我们可以通过设置和拆卸功能来实现。 这些帮助程序使我们可以在运行测试之前初始化事情,然后进行清理。

In our case, a way of doing it could be to create our wrapper before each test and destroy it afterwards.

在我们的情况下,一种方法是在每次测试之前创建包装,然后再销毁它。

let wrapper = null
beforeEach(() => {  wrapper = shallowMount(Rating, {    propsData: {      maxStars: 6,      grade: 3    }  })})
afterEach(() => {  wrapper.destroy()})
describe('Rating', () => {  // we remove the `const wrapper = …` expression  // …}

As their names suggest, beforeEach and afterEach run before and after each test, respectively. This way we can be 100% sure we’re using a fresh wrapper whenever we run a new test.

顾名思义, beforeEachafterEach分别在每个测试之前和之后运行。 这样,我们可以在每次运行新测试时100%确保使用新包装。

测试的特殊标识符 (Special identifiers for tests)

It’s never a good idea to mix selectors for styling and other purposes, such as test hooks.

混合使用选择器以进行样式设计和其他用途(例如测试挂钩)绝不是一个好主意。

What if you change the tag name or the class?

如果更改标签名称或类怎么办?

What if you don’t have a specific identifier on an element you want to test such as, in our case, the counter?

如果在要测试的元素(例如我们的计数器)上没有特定的标识符怎么办?

You don’t want to pollute your production code with classes which would be useless there. It would be much better to have dedicated hooks for tests, such as a dedicated data attribute, but only during tests. This way a mess isn’t left in the final build.

您不想用在那里没有用的类来污染您​​的生产代码。 最好有专用的钩子来进行测试,例如专用的数据属性, 但只在测试期间进行 。 这样一来,就不会在最终版本中留下混乱。

One way to handle this is to create a custom Vue directive.

一种解决方法是创建自定义Vue指令 。

The Vue instance has a directive method which takes two arguments — a name, and an object of functions for each hook of the component lifecycle when injected in the DOM. You can also pass a single function if you don’t care about a specific hook.

Vue实例具有一个directive方法,该方法带有两个参数- 名称 ,和注入到DOM 中的组件生命周期的每个挂钩的 函数对象 。 如果您不关心特定的钩子,也可以传递一个函数。

Let’s create a new directory called directives in src/, and add a test.js file. We’ll export the function we want to pass in our directive.

让我们在src/创建一个名为directives的新目录,并添加一个test.js文件。 我们将导出要传递给指令的函数。

// test.js
export default (el, binding) => {  // do stuff}

A directive hook can take several arguments and, in our case, we only need the first two: el and binding. The el argument refers to the element the directive is bound to. The binding argument is an object which contains the data we passed in the directive. This way we can manipulate the element as we like.

指令挂钩可以带有多个参数 ,在我们的例子中,我们仅需要前两个参数: elbindingel参数是指指令绑定到的元素。 binding参数是一个对象,其中包含我们在指令中传递的数据。 这样,我们可以根据需要操纵元素。

export default (el, binding) => {  Object.keys(binding.value).forEach(value => {    el.setAttribute(`data-test-${value}`, binding.value[value])  })}

We’re passing an object to our directive, so we can generate data attributes starting with data-test-. In the handler function, we iterate over each property of binding, and we set a data attribute — based on the name and value — on our element.

我们将一个对象传递给指令,因此我们可以生成以data-test-开头的数据属性。 在处理程序函数中,我们迭代binding每个属性,并在元素上设置一个基于名称和值的data属性。

Now we need to register our directive so we can use it. We can do it globally but, in our case, we’re only going to register it locally — right in our Rating.vue component.

现在我们需要注册指令,以便可以使用它。 我们可以在全球范围内进行操作,但就我们而言,我们只打算在本地进行注册-就在我们的Rating.vue组件中。

<script>import Test from '@/directives/test.js'
export default {  // …  directives: { Test },  // …}</script>

Our directive is now accessible under the v-test name. Try setting the following directive on the counter:

现在可以使用v-test名称访问我们的指令。 尝试在柜台上设置以下指令:

<span v-test="{ id: 'counter' }" v-if="hasCounter">  {{ stars }} of {{ maxStars }}</span>

Now inspect the HTML in your browser with the developer tools. Your counter should look like this:

现在,使用开发人员工具在浏览器中检查HTML。 您的柜台应如下所示:

<span data-test-id="counter">2 of 5</span>

Great, it works! Now, we don’t need this either in dev mode nor when we build the project. The sole purpose of this data attribute is to be able to target elements during tests, so we only want to set it up when we run them. For this, we can use the NODE_ENV environment variable provided by Webpack, the module bundler powering our project.

太好了! 现在,无论是在开发模式下还是在构建项目时,我们都不需要它。 此数据属性的唯一目的是能够在测试期间定位元素,因此我们只想在运行它们时进行设置。 为此,我们可以使用NODE_ENV提供的NODE_ENV环境变量,该模块是为我们的项目提供动力的模块捆绑器。

When we run tests, NODE_ENV is set to 'test'. Therefore, we can use it to determine when to set the test attributes or not.

当我们运行测试时, NODE_ENV设置为'test' 。 因此,我们可以使用它来确定何时设置测试属性。

export default (el, binding) => {  if (process.env.NODE_ENV === 'test') {    Object.keys(binding.value).forEach(value => {      el.setAttribute(`data-test-${value}`, binding.value[value])    })  }}

Refresh your app in the browser and inspect the counter again: the data attribute is gone.

在浏览器中刷新您的应用,然后再次检查计数器: data属性消失了

Now we can use the v-test directive for all elements we need to target. Let’s take our test from earlier:

现在,我们可以对需要定位的所有元素使用v-test指令。 让我们从前面进行测试:

it('adds `active` class on an inactive star when the user clicks it', () => {  const fourthStar = wrapper.findAll('[data-test-id="star"]').at(3)  fourthStar.trigger('click')  expect(fourthStar.classes()).toContain('active')})

We’ve replaced the .star selector with [data-test-id="star"], which allows us to change classes for presentation purposes without breaking tests. We get one of the benefits of the single-responsibility principle and loose coupling — when your abstractions only have a single reason to change, you avoid all kinds of pesky side-effects.

我们将.star选择器替换为[data-test-id="star"] ,这使我们可以为演示目的而更改类而不会破坏测试。 我们得到的好处之一单一职责原则和松散的耦合 -当你的抽象只有一个理由去改变,你避免各种讨厌的副作用。

我们还应该在测试的类中使用这些钩子吗? (Should we also use these hooks for the classes we test?)

After setting this directive to target elements to test, you may be wondering if you should also use them to replace the classes we actively look for. Let’s look at the assertion from our first test:

在将此指令设置为要测试的目标元素之后,您可能想知道是否还应该使用它们来代替我们积极寻找的类。 让我们看一下第一个测试的断言:

expect(wrapper.findAll('.active').length).toEqual(3)

Should we use v-test on the elements with the active class, and replace the selector in the assertion? Great question.

我们是否应该在active类的元素上使用v-test ,并在断言中替换选择器? 好问题

Unit tests are all about testing one thing at a time. The first argument of the it function is a string, with which we describe what we’re doing from a consumer perspective.

单元测试都是一次测试一件事。 it函数的第一个参数是一个字符串,我们从消费者的角度描述我们在做什么。

The test that wraps our assertion says renders a list of stars with class active equal to prop.grade. This is what the consumer expects. When they pass a number to the grade property, they expect to retrieve an equal number of active or selected stars. Yet, in our component’s logic, the active class is precisely what we use to define this trait. We assign it depending on a specific condition, so we can visually differentiate active stars from the others. Here, the presence of this specific class is exactly what we want to test.

包含断言的测试将renders a list of stars with class active equal to prop.grade. 这就是消费者的期望。 当他们将数字传递给grade属性时,他们希望检索到相等数量的活动或选定的恒星。 但是,按照组件的逻辑, active类正是我们用来定义此特征的类。 我们根据特定条件对其进行分配,因此我们可以在视觉上区分活跃恒星和其他恒星。 在这里,这个特定类的存在正是我们要测试的。

So, when deciding whether you should use a selector you already have or set a v-test directive, ask yourself the question: what am I testing, and does using this selector makes sense for a business logic perspective?

因此,在决定是否应该使用已有的选择器或设置v-test指令时,请问自己一个问题: 我正在测试什么,并且从业务逻辑角度来看,使用此选择器是否有意义?

它与功能或端到端测试有何不同? (How is it different from functional or end-to-end tests?)

At first, it might look odd to unit test components. Why would you unit test UI and user interactions? Isn’t that what functional tests are here for?

首先,对于单元测试组件而言,它看起来很奇怪。 为什么要对UI和用户交互进行单元测试? 这不是功能测试吗?

There is a fundamental yet subtle difference to make between testing a component’s public API — aka from a consumer perspective — and testing a component from a user perspective. First, let’s underline something important: we’re testing well-defined JavaScript functions, not pieces of UI.

消费者的角度测试组件的公共API(从用户角度来看)与从用户的角度测试组件之间存在根本但微妙的区别。 首先,让我们强调一些重要的事情: 我们正在测试定义明确JavaScript函数,而不是UI部分

When you look at a single-file component it’s easy to forget the component compiles into a JavaScript function. We’re not testing the underlying Vue mechanism which, from this function, causes UI-oriented side-effects like injecting HTML in the DOM. That’s what Vue’s own tests already take care of. In our case, our component is no different from any other function: it accepts input and returns an output. These causes and consequences are what we’re testing, and nothing else.

当您查看单个文件组件时,很容易忘记该组件会编译为JavaScript函数。 我们没有测试底层的Vue机制,该机制会从此函数引起面向UI的副作用,例如在DOM中注入HTML。 这就是Vue自己的测试已经解决的问题。 在我们的例子中,我们的组件与其他函数没有什么不同: 它接受输入并返回输出 。 这些因果关系是我们正在测试的,仅此而已。

What’s confusing is that our tests look a bit different from regular unit tests. Usually, we write things like:

令人困惑的是我们的测试看起来与常规单元测试有些不同。 通常,我们这样写:

expect(add(3)(4)).toEqual(7)

There’s no debate here. Input and output of data, that’s all we care about. With components, we’re expecting things to render visually. We’re traversing a virtual DOM and testing for the presence of nodes. That’s also what you do with functional or end-to-end tests, with tools like Selenium or Cypress.io. So how does that differ?

这里没有辩论。 数据的输入和输出,这就是我们关心的全部。 对于组件,我们期望事物能够以可视方式呈现。 我们正在遍历虚拟DOM并测试节点的存在。 您也可以使用Selenium或Cypress.io之类的工具来进行功能或端到端测试。 那有什么不同呢?

You need not to confuse what we’re doing to fetch the data we want to test and the actual purpose of the test. With unit tests, we’re testing isolated behaviors. With functional or end-to-end tests, we’re testing scenarios.

你不必混淆我们正在做的事情来获取我们想要的测试和试验的实际目的的数据。 通过单元测试,我们正在测试孤立的行为。 通过功能测试或端到端测试,我们正在测试场景

A unit test makes sure a unit of the program behaves as expected. It’s addressed to the consumer of the component — the programmer who uses the component in their software. A functional test ensures a feature or a workflow behaves as expected, from a user perspective — the final user, who consumes the full software.

单元测试可确保程序的单元行为符合预期。 它面向的是组件的使用者 -在其软件中使用该组件的程序员。 从用户的角度(即使用完整软件的最终用户)的角度出发,功能测试可确保功能工作流程的行为符合预期。

更进一步 (Going further)

I won’t go into the detail of each test, because they all share a similar structure. You can find the full spec file on GitHub, and I strongly recommend you try to implement them yourself first. Software testing is an art as much as it is a science, and requires twice as much practice as it requires theory.

我不会详细介绍每个测试,因为它们都具有相似的结构。 您可以在GitHub上找到完整的规范文件 ,我强烈建议您尝试首先自己实现它们。 软件测试既是一门科学,又是一门科学,它需要的实践是理论的两倍。

Don’t worry if you didn’t get everything, or if you struggle with writing your first tests: testing is notoriously hard. Also, if you have a question, don’t hesitate to hit me up on Twitter!

如果您一无所获,也不必担心编写第一个测试的麻烦: 众所周知,测试很难 。 另外,如果您有任何疑问,请随时在Twitter上与我联系!

Originally published at frontstuff.io.

最初发布在frontstuff.io上 。

翻译自: https://www.freecodecamp.org/news/how-to-unit-test-your-first-vue-js-component-14db6e1e360d/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/392953.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Asp.NetCoreWebApi - RESTful Api

REST 常用http动词 WebApi 在 Asp.NetCore 中的实现3.1. 创建WebApi项目.3.2. 集成Entity Framework Core操作Mysql 3.2.1. 安装相关的包(为Xxxx.Infrastructure项目安装)3.2.2. 建立Entity和Context3.2.3. ConfigureService中注入EF服务3.2.4. 迁移数据库3.2.5. 数据库迁移结果…

android动画影子效果,Android TV常用动画的效果,View选中变大且有阴影(手机也能用)...

因为电视屏幕比较大&#xff0c;而我们看电视时距离电视有一定距离&#xff0c;这样就需要动画效果比较明显&#xff0c;这个动画就是应用最广泛的&#xff0c;因为很酷&#xff0c;呵呵&#xff0c;你懂得&#xff0c;看了就知道。效果如下图&#xff1a;public class MainAct…

leetcode226. 翻转二叉树(dfs)

翻转一棵二叉树。示例&#xff1a;输入&#xff1a;4/ \2 7/ \ / \ 1 3 6 9 输出&#xff1a;4/ \7 2/ \ / \ 9 6 3 1代码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode righ…

Java BigDecimal Rounding Mode

UP        往绝对值大了取 DOWN      往绝对值小了取 CEILING     往值大了取 FLOOR      往值小了取 HALF_UP     不管正负&#xff0c;四舍五入 HALF_DOWN  不管正负&#xff0c;五舍六入 HALF_EVEN    整数部分为奇数&#xff1a;四舍五入…

如何成为一名有效的软件工程师

by Luis Santiago路易斯圣地亚哥(Luis Santiago) 如何成为一名有效的软件工程师 (How to become an effective software engineer) When I first started my journey as a software engineer I quickly noticed the great amount of cognitive load involved when working on …

linux 高可用----keepalived+lvs

什么是高可用&#xff1f; HA&#xff08;high availability&#xff09;即高可用性&#xff1b;就是在高可用集群中发生单点故障时&#xff0c;能够自动转移资源并切换服务&#xff0c;以保证服务一直在线的机制。 LVS LVS&#xff1a;&#xff08;linux virtual server&#…

用户配置相关文件

用户配置相关文件小总结 /etc/passwd 记录用户相关的信息 /etc/shadow 密码影子文件 /etc/group 记录用户组相关的信息 /etc/gshadow 密码影子文件&#xff08;组密码&#xff09; /etc/passwd 文件中各段的内容 第1段&#xff1a;用户名 第…

华为5c android n风格,华为荣耀畅玩5C的屏幕怎么样

华为荣耀畅玩5C的屏幕怎么样屏幕方面&#xff0c;华为荣耀畅玩5C采用了5.2英寸1080P级别GFF贴合屏幕&#xff0c;塑料边框采用了弧面状的设计&#xff0c;握感比较舒适。华为荣耀畅玩5C采用了双主天线的设计&#xff0c;分别在上下的塑料区域。此外&#xff0c;边框以及后盖的上…

spring解析配置文件(三)

一、从XmlBeanDefinitionReader的registerBeanDefinitions&#xff08;doc,resource&#xff09;开始 1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) 2 throws BeanDefinitionStoreException { 3 try { 4 …

leetcode968. 监控二叉树(dfs)

给定一个二叉树&#xff0c;我们在树的节点上安装摄像头。 节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。 计算监控树的所有节点所需的最小摄像头数量。 输入&#xff1a;[0,0,null,0,0] 输出&#xff1a;1 解释&#xff1a;如图所示&#xff0c;一台摄像头足…

linux系统部署war包,查看tomcat日志

1.部署war包app/tomcat/bin在tomcat/bin 目录下启动 .startup.sh&#xff0c;在启动过程中tomcat会对war包进行解压&#xff0c;形成相应的项目目录 执行命令&#xff1a;./startup.sh 2.实时查看tomcat的日志。首先需要到tomcat的日志目录下。我的目录供你参考app/tomcat/logs…

代码编写工具_这些工具将帮助您编写简洁的代码

代码编写工具看一下Prettier&#xff0c;ESLint&#xff0c;Husky&#xff0c;Lint-Staged和EditorConfig (A look at Prettier, ESLint, Husky, Lint-Staged and EditorConfig) Learning to write good code, but you don’t know where to start… Going through style-guide…

使用kibana和elasticsearch日志实时绘制图表

前言&#xff1a; 此文接的是上篇&#xff0c;上次的内容是&#xff0c;用python操作elasticsearch存储&#xff0c;实现数据的插入和查询。 估计有些人一看我的标题&#xff0c;以为肯定是 logstash kibana elasticsearch的组合。这三个家伙也确实总是勾搭在一块。 其实logst…

android中设置菜单栏,android – 菜单项没有显示在操作栏

我做了一个全新的项目。我已经添加了项目到菜单布局文件。这些项目不会显示在操作栏的右侧。我记得一个有三个点的图标显示出来&#xff0c;打开菜单。这里是我的活动public class MainActivity extends Activity {Overrideprotected void onCreate(Bundle savedInstanceState)…

leetcode617. 合并二叉树(dfs)

给定两个二叉树&#xff0c;想象当你将它们中的一个覆盖到另一个上时&#xff0c;两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠&#xff0c;那么将他们的值相加作为节点合并后的新值&#xff0c;否则不为 NULL 的节点将直接…

conda使用报错:ImportError:DLL load failed

conda安装python环境经常报&#xff1a; ImportError:DLL load failed 将环境变量加入path可以解决&#xff1a; D:\program\anaconda D:\program\anaconda\Scripts D:\program\anaconda\Library\bin 转载于:https://www.cnblogs.com/timlong/p/11122805.html

《程序员修炼之道》笔记(八)

第八章 注重实效的项目 随着你的项目开动&#xff0c;我们需要从个体的哲学和编码问题转向讨论更大的、项目级的问题。我们将不深入项目管理的具体细节&#xff0c;而是要讨论能使项目成功或失败的几个关键区域。 1. 注重实效的团队 书中前面的内容都是帮助个体成为更好的程序员…

android 网络调试 源代码,Android源代码调试环境搭建

我们在调试Android应用程序的时候&#xff0c;有时候遇到一些莫名其妙的问题&#xff0c;因此我们需要查看Android内部是如何调用的。我们都知道Android是一个伟大的开源项目&#xff0c;因此debug的时候肯定是支持源代码级别调试的。采用源代码调试&#xff0c;一方面有利于发…

如何使用HTTP压缩优化服务器

鉴于互联网上的宽带有限&#xff0c;网络管理人员任何旨在加速接入速度的努力都是有价值的。其中的一个方法就是通过HTTP压缩技术实现接入速度的加速&#xff0c;它通过减少在服务器和客户端之间传输的数据量&#xff0c;显著地提高网站的性能。数据压缩本身并不新鲜。但是&…

leetcode117. 填充每个节点的下一个右侧节点指针 II(dfs)

给定一个二叉树 struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针&#xff0c;让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点&#xff0c;则将 next 指针设置为 NULL。 初始状态下&#xff0c;所有 next 指针都被设置为 …