如何对Vue.js应用程序进行自动测试

252 阅读7分钟

本教程包括

  1. 创建和设置一个Vue.js应用程序
  2. 为Vue组件编写自动化测试
  3. 建立一个持续集成管道

作为JavaScript社区的领先框架之一,Vue.js是一个渐进式框架,用于为Web用户界面构建可重用的组件。其直观的API和处理前端逻辑的强大灵活性只是Vue被全球开发者采用的两个原因。

在本教程中,我将带领你建立一个简单的列表应用程序,显示用户的名字和角色。我将告诉你如何为该应用编写测试。最后,你将配置一个持续集成管道以实现自动化测试。

先决条件

对于本教程,你将需要。

开始学习

你将通过使用Vue CLI创建一个新的Vue.js项目。在终端上运行这个命令。

vue create vue-user-app

你会被提示回答几个问题。在本教程中,使用这里显示的回答。

  • 请选择一个预设:手动选择功能
  • 勾选你的项目所需的功能:Babel, Linter, Unit
  • 选择一个Vue.js的版本,你想用3.x来启动项目
  • 选择一个linter/formatter配置。只用ESLint来预防错误
  • 选择额外的lint功能:保存时提示
  • 选择一个单元测试解决方案:Jest
  • 你喜欢把Babel、ESLint等的配置放在哪里?在专门的配置文件中
  • 把这个作为预设保存起来,供以后的项目使用?没有

Vue CLI将按照你指定的方式安装Vue应用程序及其依赖项。

转到新项目,使用这些命令运行它。

cd vue-user-app

npm run serve

你可以在浏览器中查看该应用程序,网址是http://localhost:8080

Vue homepage

这将渲染一个新的Vue.js应用程序的默认主页。你将在本教程的下一节中通过创建新的可重用组件来改变这一点。

使用CTRL + C停止应用程序的运行。

创建可重复使用的组件

Vue.js组件包含三个不同的部分,用于构建网络应用。它们是。

  • <template></template>
  • <script></script>
  • <style></style>

这些部分有助于为视图、业务逻辑和造型创建一个合适的结构。

创建用户组件

你将添加到应用程序的第一个组件是用于创建和列出用户。这个组件包含一个带有输入字段的表单,以接受特定用户的名字。当表单被提交时,输入字段的详细信息被推送到一个为测试目的而创建的假的users 数组。

首先,在./src/components 文件夹中创建一个名为UserList.vue 的新文件。打开这个新文件并粘贴这个内容。

<template>
  <div class="container">
    <div class="page-title">
      <h3>{{ message }}</h3>
    </div>
    <div class="row">
      <div
        class="col-md-4"
        v-for="user in users"
        :key="user.id"
        data-user="user"
      >
        <div class="m-portlet m-portlet--full-height">
          <div class="m-portlet__body">
            <div class="tab-content">
              <div class="tab-pane active" id="m_widget4_tab1_content">
                <div class="m-widget4 m-widget4--progress">
                  <div class="m-widget4__item">
                    <div class="m-widget4__img m-widget4__img--pic">
                      <img
                        src="https://bootdey.com/img/Content/avatar/avatar1.png"
                        alt=""
                      />
                    </div>
                    <div class="m-widget4__info">
                      <span class="m-widget4__title"> {{ user.name }} </span>
                      <br />
                      <span class="m-widget4__sub">
                        {{ user.title }}
                      </span>
                    </div>
                    <div class="m-widget4__ext">
                      <button
                        @click="deleteUser(user)"
                        class="btn btn-primary"
                        data-cy="taskDelete"
                        id="deleteForm"
                      >
                        Delete
                      </button>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="row">
      <form id="form" @submit.prevent="createUser">
        <input id="new-user" v-model="newUser" class="form-control" />
      </form>
    </div>
  </div>
</template>

这是<template></template> 部分,将用户列表渲染到视图中。它还包含一个输入字段,用于发布新用户的名字。

接下来,在</template> 标签的末尾粘贴这段代码。

<script>
export default {
  props: ["message"],
  data() {
    return {
      newUser: "",
      users: [
        {
          id: 1,
          name: "Anna Strong",
          title: "Software Engineer",
        },
        {
          id: 2,
          name: "John Doe",
          title: "Technical Writer",
        },
      ],
    };
  },
  methods: {
    createUser() {
      this.users.push({
        id: 3,
        name: this.newUser,
        title: "Crypto Expert",
      });
      this.newUser = "";
    },

    deleteUser(user) {
      const newList = this.users.filter((u) => user.id !== u.id);
      this.users = newList;
    },
  },
};
</script>

这定义了一个users 数组,其中包含将在页面上呈现的假数据。createUser() 方法通过输入字段接收新用户的详细信息,并将其推送到users 数组中。你还定义了一个名为deleteUser() 的方法,它接受一个user 对象作为参数,并在调用时将其从用户列表中删除。

创建页眉组件

要为视图的标题部分创建一个组件,请进入./src/components 文件夹,创建一个名为NavBar.vue 的新文件。将这段代码粘贴到其中。

<template>
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div
      class="collapse navbar-collapse justify-content-md-center"
      id="navbarsExample08"
    >
      <ul class="navbar-nav">
        <li class="nav-item active">
          <a class="nav-link" href="#">
            Users Listing App <span class="sr-only">(current)</span></a
          >
        </li>
      </ul>
    </div>
  </nav>
</template>

更新应用程序组件

打开应用程序的AppComponent ,并更新它,包括与NavBarUserList 两个组件的链接。用这个替换它的内容。

<template>
  <div>
    <NavBar />
    <UserList />
    <div class="container"></div>
  </div>
</template>

<script>
import NavBar from "./components/NavBar.vue";
import UserList from "./components/UserList.vue";

export default {
  name: "App",
  components: { NavBar, UserList },
};
</script>

<style>
body {
  background: #eee;
}
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
.page-title {
  margin: 15px 15px;
}
.m-portlet {
  margin-bottom: 2.2rem;
}
.m-portlet {
  -webkit-box-shadow: 0 1px 15px 1px rgba(113, 106, 202, 0.08);
  -moz-box-shadow: 0 1px 15px 1px rgba(113, 106, 202, 0.08);
  box-shadow: 0 1px 15px 1px rgba(113, 106, 202, 0.08);
  background-color: #fff;
}
.m-portlet .m-portlet__head {
  border-bottom: 1px solid #ebedf2;
}
.m-widget4 .m-widget4__item {
  display: table;
  padding-top: 1.15rem;
  padding-bottom: 1.25rem;
}
.m-widget4 .m-widget4__item .m-widget4__img {
  display: table-cell;
  vertical-align: middle;
}
.m-widget4 .m-widget4__item .m-widget4__img.m-widget4__img--logo img {
  width: 3.5rem;
  border-radius: 50%;
}
.m-widget4 .m-widget4__item .m-widget4__img.m-widget4__img--pic img {
  width: 4rem;
  border-radius: 50%;
}
.m-widget4 .m-widget4__item .m-widget4__img.m-widget4__img--icon img {
  width: 2.1rem;
}
.m-widget4 .m-widget4__item .m-widget4__info {
  display: table-cell;
  width: 100%;
  padding-left: 1.2rem;
  padding-right: 1.2rem;
  font-size: 1rem;
  vertical-align: middle;
}
.m-widget4 .m-widget4__item .m-widget4__info .m-widget4__title {
  font-size: 1rem;
  font-weight: bold;
}
.m-widget4.m-widget4--progress .m-widget4__info {
  width: 50%;
}
</style>

这包括一个<style></style> 部分,以包括应用程序的样式。

包括Bootstrap

打开公共文件夹中的index.html 文件,包括Bootstrap的CDN文件。这只是为了给页面提供一些默认样式。

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
      integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn"
      crossorigin="anonymous"
    />
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong
        >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
        properly without JavaScript enabled. Please enable it to
        continue.</strong
      >
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

现在,用npm run serve 再次运行该应用程序。访问https://localhost:8080User Listing App

现在你的应用程序已经启动并运行,你可以开始对UserList 组件进行单元测试。

Vue.js组件的单元测试

有很多很多JavaScript应用程序的测试框架。Jest作为最受欢迎的框架之一脱颖而出。对于Vue.js,Vue Test Utils(VTU)是首选的测试库。这是有道理的,因为VTU测试库是建立在Jest之上的。它被设计为通过提供实用功能来简化Vue.js组件的测试。

当你创建这个项目并选择Jest作为单元测试解决方案时,Vue CLI安装了vue-test-utilsjest ,和其他测试库。以下目录也被创建了。

  • test/unit:这个目录将放置所有的单元测试。一旦发出测试命令,Jest将在这里搜索你的单元测试文件。

编写应用程序的测试

在本节中,我们将为UserList 组件编写单元测试。在该组件中,我们要。

  • 挂载该组件,并检查它是否能渲染传递给它的道具。
  • 在组件中寻找元素并渲染用户列表。
  • 提交一个表单,然后创建一个新的用户并将其添加到现有用户列表中。

首先,到test/unit 文件夹中,将example.spec.js 文件重命名为user.spec.js 。打开该文件,将其内容替换为以下内容。

import { mount } from "@vue/test-utils";
import UserList from "@/components/UserList.vue";

describe("User List component unit tests: ", () => {
  it("renders props when passed", () => {
    const message = "new message";
    const wrapper = mount(UserList, {
      props: { message },
    });
    expect(wrapper.text()).toMatch(message);
  });

  test("Renders the list", () => {
    const wrapper = mount(UserList);
    const name = "Anna Strong";
    const user = wrapper.get('[data-user="user"]');
    expect(user.text()).toContain(name);
    expect(wrapper.findAll('[data-user="user"]')).toHaveLength(2);
  });

  test("creates a user", async () => {
    const wrapper = mount(UserList);
    const newName = "John Doe";
    await wrapper.get('[id="new-user"]').setValue(newName);
    await wrapper.get('[id="form"]').trigger("submit");
    expect(wrapper.findAll('[data-user="user"]')).toHaveLength(3);
  });
});

在这个文件中,我们从vue-test-utils 库中导入了一个名为mount 的函数,以帮助我们装载一个UserList 组件的实例。

我们首先写了一个测试,断言该组件可以渲染一个从父组件传入的道具。接下来,我们在UserList 组件的视图中锁定了数据属性,确保它包含一个用户的具体名字,并确保它渲染了users 数组中的默认长度。

最后,我们创建了一个测试函数,以确保在该组件中可以创建一个新的用户。

在本地运行测试

为了确认定义的测试是否通过,从终端输入这个命令。

npm run test:unit

这是终端的输出。

> vue-user-app@0.1.0 test:unit
> vue-cli-service test:unit

 PASS  tests/unit/user.spec.js
  User List component unit tests:
    ✓ renders props when passed (33 ms)
    ✓ Renders the list (19 ms)
    ✓ creates a user (27 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        0.924 s, estimated 1 s
Ran all test suites.

Terminal test result

在下一节中,你将使用CircleCI自动进行测试。

自动测试

在本节中,你将为你的项目的持续集成管道创建一个配置文件。

在项目的根部创建一个.circleci 文件夹,并在其中创建一个名为config.yml 的新文件。添加这个内容。

version: 2.1
jobs:
  build-and-test:
    working_directory: ~/project
    docker:
      - image: cimg/node:17.4.0
    steps:
      - checkout
      - run:
          name: Update NPM
          command: "sudo npm install -g npm"
      - restore_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
      - run:
          name: Install Dependencies
          command: npm install --legacy-peer-deps
      - save_cache:
          key: dependency-cache-{{ checksum "package-lock.json" }}
          paths:
            - ./node_modules
      - run:
          name: Run test for the application
          command: npm run test:unit
workflows:
  build-and-test:
    jobs:
      - build-and-test

这个文件定义了一个作业,用于为你的项目构建和运行测试命令。这个作业

  • 从CircleCI Docker镜像注册表中调取cimg/node:17.4.0 Docker镜像
  • 使用该镜像来安装项目的所有依赖项
  • 运行测试

现在,配置文件已经被正确设置,你需要在GitHub上设置一个仓库,并将项目链接到CircleCI。查看推送项目到GitHub的步骤说明。

在CircleCI上设置项目

用链接的GitHub账户登录您的CircleCI账户,在项目的仪表板上查看您的所有仓库。搜索vue-user-app 项目,点击设置项目继续。

Select project

你会被提示选择一个配置文件。在你的 repo 中选择.circleci/config.yml 文件,并输入存储你的代码的分支名称。点击 "设置项目"来启动工作流。

Select config file

这将初始化工作流并为你的项目运行测试。

Successful workflow

总结

在本教程中,我们用Vue.js构建了一个列表应用程序,并涵盖了为其组件编写单元测试的必要步骤。然后,我们使用CircleCI基础设施来配置一个持续集成管道,以实现测试的自动化。