知道要测试什么——Vue组件单元测试

关于单元测试Vue组件,我看到的最常见的问题是“我到底应该测试什么?”

虽然测试过多或过少都是可能的,但我的观察是,开发人员通常会在测试过多时犯错误。毕竟,没有人愿意成为一个组件测试不足导致应用程序在生产中崩溃的人。

在本文中,我将与您分享一些用于单元测试组件的指导原则,这些指导原则确保我不会永远编写测试,但是提供了足够的覆盖率,使我不会遇到麻烦。

我假设您已经了解了Jest和Vue测试Utils。

示例组件

在学习指导原则之前,让我们首先熟悉我们将要测试的以下示例组件。它叫做Item.vue,是电子商务应用中的产品项目。

Item.vue

<template>
  <div>
    <h2>{{ item.title }}</h2>
    <button @click="addToCart">Add To Cart</button>
    <img :src="item.image"/>
  </div>
</template>
<script>
export default {
  name: "Item",
  props: [ "id" ],
  computed: {
    item () {
      return this.$store.state.find(
        item => item.id === this.id
      );
    }
  },
  methods: {
    addToCart () {
      if (this.$auth.check()) {
        this.$store.commit("ADD_TO_CART", this.id);
      } else {
        this.$router.push({ name: "login" });
      }
    }
  }
};
</script>

规范文件设置

下面是测试的规范文件。在其中,我们将使用Vue Test Utils浅挂载组件,因此我已经导入了它,以及我们正在测试的Item组件。

我还创建了一个工厂函数,它将生成一个可覆盖的配置对象,这样我们就不必在每个测试中指定道具和模拟三个依赖项。

item.spec.js

import { shallowMount } from "@vue/test-utils";
import Item from "@/components/Item";

function createConfig (overrides) {
  const id = 1;
  const mocks = {
    // Vue Auth
    $auth: {
      check: () => false
    },
    // Vue Router
    $router: {
      push: () => {}
    },
    // Vuex
    $store: {
      state: [ { id } ],
      commit: () => {}
    }
  };
  const propsData = { id };
  return Object.assign({ mocks, propsData }, overrides);
}

describe("Item.vue", () => {
  // Tests go here
});

确定业务逻辑

关于要测试的组件,要问的第一个也是最重要的问题是“什么是业务逻辑?”换句话说,组件的作用是什么?

对于Item.vue,这是业务逻辑:

  • 它将根据接收到的id道具显示一个项目

  • 如果用户是访客,单击Add to Cart按钮将其重定向到登录页面

  • 如果用户已登录,单击Add to Cart按钮将触发Vuex突变ADD_TO_CART

识别输入和输出

当您对组件进行单元测试时,您将其视为一个黑盒。方法、计算属性等中的内部逻辑只影响输出。

所以,下一个重要的事情是确定组件的输入和输出,因为这些也是测试的输入和输出。

在Item.vue的情况下,输入是:

  • id道具

  • 来自Vuex和Vue Auth的声明

  • 用户通过单击按钮输入

而输出为:

  • 呈现标记

  • 数据发送到Vuex突变或Vue路由器推送

有些组件还可以将表单和事件作为输入,并将事件作为输出发出。

测试1:当客户单击按钮时调用路由器

一个业务逻辑是“如果用户是访客,单击添加到购物车按钮会将他们重定向到登录页面”。让我们为此写一个测试。

我们将通过浅层安装组件来设置测试,然后找到并单击Add to Cart按钮。

test("router called when guest clicks button", () => {
  const config = createConfig();
  const wrapper = shallowMount(Item, config);
  wrapper
    .find("button")
    .trigger("click");
  // Assertion goes here
}

我们稍后将添加一个断言。

不要超出输入和输出的边界

在这个测试中,我们很有可能会在单击按钮后检查路由是否更改为登录页面的路由,例如。

import router from "router";

test("router called when guest clicks button", () => {
  ...
  // Wrong
  const route = router.find(route => route.name === "login");
  expect(wrapper.vm.$route.path).toBe(route.path);
}

虽然这确实隐式地测试了组件输出,但是它依赖于路由器来工作,这不应该是这个组件所关心的。

最好直接测试这个组件的输出,即对$router.push的调用。路由器是否完成该操作超出了此特定测试的范围。

因此,让我们监视路由器的push方法,并断言它是用login route对象调用的。

import router from "router";

test("router called when guest clicks button", () => {
  ...
  jest.spyOn(config.mocks.$router, "push");
  const route = router.find(route => route.name === "login");
  expect(spy).toHaveBeenCalledWith(route);
}

测试2:vuex在auth用户单击按钮时调用

接下来,让我们测试“如果用户已登录,单击Add to Cart按钮将触发Vuex突变ADD_TO_CART”的业务逻辑。

要重复上面的教训,您不需要检查Vuex状态是否被修改。我们将对Vuex商店进行单独的测试来验证这一点。

这个组件的工作就是提交,所以我们只需要测试它就可以了。

首先重写$auth。检查mock,使其返回true(对于已登录的用户也是如此)。然后,我们将监视存储的提交方法,并断言它是在单击按钮后调用的。

test("vuex called when auth user clicks button", () => {
  const config = createConfig({
    mocks: {
      $auth: {
        check: () => true
      }
    }
  });
  const spy = jest.spyOn(config.mocks.$store, "commit");
  const wrapper = shallowMount(Item, config);
  wrapper
    .find("button")
    .trigger("click");
  expect(spy).toHaveBeenCalled();
}

不要测试其他库的功能

Item组件显示存储项的数据,特别是标题和图像。也许我们应该写一个测试来专门检查这些?例如:

test("renders correctly", () => {
  const wrapper = shallowMount(Item, createConfig());
  // Wrong
  expect(wrapper.find("h2").text()).toBe(item.title);
}

这是另一个不必要的测试,因为它只是测试Vue从Vuex中获取数据并将其插入到模板中的能力。Vue库已经对该机制进行了测试,所以您应该依赖于它。

测试3:正确渲染

但是如果有人不小心将title重命名为name,然后忘记更新插值表达式怎么办?这难道不值得测试吗?

是的,但如果你像这样测试模板的每个方面,你会在哪里停止?

测试标记的最佳方法是使用快照测试来检查整体渲染输出。这不仅包括标题插值,还包括图像,按钮文本,任何类等。

test("renders correctly", () => {
  const wrapper = shallowMount(Item, createConfig());
  expect(wrapper).toMatchSnapshot();
});

下面是一些其他不需要测试的例子:

  • 如果src属性绑定到img元素

  • 如果添加到Vuex存储中的数据与插入的数据相同

  • 如果计算的属性返回正确的项

  • 如果路由器推送重定向到正确的页面

总结

我认为这三个相对简单的测试对于这个组件来说足够了。

除非另有证明,否则在单元测试组件进行测试时需要有良好的思维方式。

以下是您可以自问的问题:

  • 这是业务逻辑的一部分吗?

  • 这是否直接测试组件的输入和输出?

  • 这是测试我的代码还是第三方代码?

英文原文地址:https://vuejsdevelopers.com/2019/08/26/vue-what-to-unit-test-components/

以上就是知道要测试什么——Vue组件单元测试的详细内容,更多请关注web前端其它相关文章!

赞(0) 打赏
未经允许不得转载:web前端首页 » Vue.js 教程

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

前端开发相关广告投放 更专业 更精准

联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏