一文带你学习前端 - 自动化测试

news2024/11/27 10:42:22

theme: devui-blue

前端自动化测试

1. 自动化测试基本概念介绍

前言

一般我们实现功能,基本都是两部分写代码,调试/测试。写代码和测试的时间,基本都是55分。如果是测试逻辑,可能要打一下log,或者打断点去调试。测试ui和逻辑,可能要点击界面进行交互,然后再测试逻辑,总之都是在手动测试。今天我给大家唠唠自动化测试

未命名文件.png

1.1黑盒测试和白盒测试

  • 黑盒测试一般也被称为功能测试,黑盒测试要求测试人员将程序看作一个整体,不考虑其内部结构和特性,只是按照期望验证程序是否能正常工作(点点点,达到预期就行)
  • 白盒测试是基于代码本身的测试,一般指对代码逻辑结构的测试(自动化化测试或者说自己测自己)

1.2测试分类

单元测试(Unit Testing)

单元测试是指对程序中最小可测试单元进行的测试,例如测试一个函数一个模块一个组件

  • tip: 所以我们的组件库,特别适合单测。一些重要的模块,比如用户管理,支付管理,购物车管理…

集成测试(Integration Testing)

将已测试过的单元测试函数进行组合集成暴露出的高层函数或类的封装,对这些函数或类进行的测试。

  • tip:集成测试通常在单元测试完成后进行。常见的集成测试包括:增量式测试,自顶向下测试

端到端测试(E2E Testing) 打开应用程序模拟输入,检查功能以及界面是否正确,比如puppeteer,Selenium,Cypress

1.3 TDD & BDD

TDD是测试驱动开发(Test-Driven Development)

TDD的原理是在开发功能代码之前,先编写单元测试用例代码

BDD是行为驱动开发(Behavior-Driven Development)

开会出需求,制作ui,开发,QA测试

总结: TDD是先写测试在开发 (一般都是单元测试,白盒测试),而BDD则是按照用户的行为来开发,再根据用户的行为编写测试用例 (一般都是集成测试,黑盒测试)

1.4 测试框架

  • Karma Karma为前端自动化测试提供了跨浏览器测试的能力,可以在浏览器中执行测试用例
  • Mocha 前端自动化测试框架,需要配合其他库一起使用,像chai、sinon…
  • Jest Jest 是facebook推出的一款测试框架,集成了 Mocha,chai,jsdom,sinon等功能。
  • Vitest Vitest 是一个相对较新的测试框架,专为 Vue (包括 Vue 2 和 Vue 3) 和 Vite 项目而生。它使用了 Vite 的优势,创建了一个更快、更现代的、易于设置的测试环境。

2. Jest核心应用

http://csdn.net/weix/?a=1&b=2

比如我们现在要实现一个url的解析参数你会想到几种方式 ?

  • 先来体验下手动测试

image.png

我们每写完一个功能,会先手动测试功能是否正常,测试后可能会将测试代码注释起来。这样会产生一系列问题,因为会污染源代码,所有的测试代码和源代码混合在一起。如果删除掉,下次测试还需要重新编写。

所以测试框架就帮我们解决了上述的问题

2.1 分组、用例

Jest 是基于模块的,我们需要将代码包装成模块的方式,分别使用export 将parser ,stringify 这两个方法导出

安装jest

npm init -y # 初始化pacakge.json
npm i jest 

我们建立一个qs.test.js来专门编写测试用例,这里的用例你可以认为就是一条测试功能 (后缀要以.test.js结尾,这样jest测试时默认会调用这个文件)

常用API: describe,it,expect,匹配器

  1. describedescribe 函数用于将一组相关的测试用例组织在一起。它接受两个参数:一个描述性的字符串,用于描述测试组的目的;一个回调函数,包含我们要运行的测试代码。回调函数中通常包含一个或多个 it 函数。
describe('这是一个测试组的描述', () => {
  // 这里放置测试代码
});

2. itit 函数(也可以使用 test 函数)表示一个具体的测试用例。它同样接受两个参数:一个描述性的字符串,用于描述测试用例的目的;一个回调函数,包含我们要验证的代码块。回调函数中通常包含一个或多个 expect 函数。

it('这是一个测试用例的描述', () => {
  // 这里放置要验证的代码
});

3. expectexpect 函数用于实际执行断言,检查代码的实际输出是否符合预期。它接受一个待测试的值,然后可以与一个“匹配器”(matcher)一起使用来检查预期结果。

expect(实际值).匹配器(预期值);

image.png

通过配置scripts 来执行命令

"scripts": {
    "test": "jest"
}·

这个时候会报错,因为node环境下不支持es6模块的语法,需要babel转义,当然你也可以直接使用commonjs规范来导出方法,因为大多数现在开发都采用es6模块,所以就安装一下~

# core是babel的核心包 preset-env将es6转化成es5
npm i @babel/core @babel/preset-env --save-dev

并且配置.babelrc文件,告诉babel用什么来转义

{
    "presets":[
        [
            "@babel/preset-env",{
                "targets": {"node":"current"}
            }
        ]
    ]
}

image.png

2.2 matchers匹配器

  • 主要三部分: 相等、不等、是否包含

image.png

2.3 测试操作节点方法

export const removeNode = (node) => {
    node.parentNode.removeChild(node)
};
import { removeNode } from "../dom";
it("测试删除节点- 创建一个元素,期望不是Null,删除。重新获取,断言是他是null", () => {
  document.body.innerHTML = '<div id="test"><div id="test1"></div>';
  let div = document.getElementById("test");
  expect(div).not.toBeNull();
  removeNode(div);
  //   removeNode(document.body);
  div = document.getElementById("test");
  expect(div).toBeNull();
});

image.png

常用命令

  • 只测试变化的文件 watchAll
  • 只测试哪一个 only
"scripts": {
    "test": "jest --watchAll"
}

3. Jest进阶

2.1 异步函数的测试

异步函数的两种情况: 回调函数 和 promise

// 异步代码测试
export const getDateCallback = (cb) => {
  setTimeout(() => {
    cb({ name: "wd" });
  }, 3000);
};
export const getDataPromise = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ name: "wd" });
    }, 3000);
  });
};

test

import { getDataPromise, getDateCallback } from "../3.async";

describe("description", () => {
  it.only("测试传入回调函数 获取异步返回结果", () => {
    getDateCallback((data) => {
      expect(data).toEqual({ name: "wd" });
    });
  });
});

result:

image.png

明明设置的三秒,为什么感觉没走? 因为不支持异步,希望等待结果完成再调用 done

import { getDataPromise, getDateCallback } from "../3.async";

describe("description", () => {
 it.only("测试传入回调函数 获取异步返回结果", (done) => {
   getDateCallback((data) => {
     expect(data).toEqual({ name: "wd" });
     done()
   });
 });
});

image.png
jest 中 promsie 该如何处理异步调用呢

方式一

it("测试promise done", (done) => {
    return getDataPromise().then((data) => {
      expect(data).toEqual({ name: "wd" });
      done();
    });
  });

方式二

  it("测试promise async + await", async () => {
    let data = await getDataPromise();
    expect(data).toEqual({ name: "wd" });
  });

3.2 Jest 的 mock

看一个demo,将异步的时间调长

image.png

mock: 真函数不靠谱,用假函数。

3.2.1 模拟Timer

jest.useFakeTimers(); // 创建出一个模拟的timer
    jest.runAllTimers(); // 运行所有的定时器
    jest.advanceTimersByTime(5000); // 跳过多少毫秒
    jest.runOnlyPendingTimers(); // 只运行当前等待的timer ‼️

我们这里用

image.png

image.png

虽然设置了很长的时间,但是我们使用mock 来模拟timer ,所以就直接变成同步执行了

4. Jest钩子函数

为了测试的便利,Jest中也提供了类似于Vue一样的钩子函数,可以在执行测试用例前或者后来执行

  • beforeAll 在所有测试用例执行前执行
  • afteraAll 在所有测试用例执行后
  • beforeEach 在每个用例执行前
  • afterEach 在每个用例执行后

5. Jest配置文件,测试覆盖率

npx jest --init
"scripts": {
    "test": "jest --coverage"
}

可以直接执行npm run test,此时我们当前项目下就会产生coverage报表来查看当前项目的覆盖率

image.png

  • Stmts表示语句的覆盖率
  • Branch表示分支的覆盖率(if、else)
  • Funcs函数的覆盖率
  • Lines代码行数的覆盖率

5. Vue 中集成Jest

Vue Test Utils

在测试数据为空时,测试用例没有进行等待,直接断言了结果。由于 Vue.js 异步更新 DOM 的特性,如果不等待更新完成,测试的结果可能是不准确的。

5.1 测试HellowWorld组件

HellowWorld

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>
<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

test

import Vue from "vue";

import HelloWorld from "@/components/HelloWorld.vue";

describe("测试HelloWolrd 组件", () => {
  it("传入 msg 属性看能否渲染到h1标签内", () => {

    const baseExtend = Vue.extend(HelloWorld);
    // 获取当前组件的构造函数,并且挂载此组件
    const vm = new baseExtend({
      propsData: {
        msg: "hello"
      }
    }).$mount();
    expect(vm.$el.innerHTML).toContain("hello");
  });
});

是不是有点麻烦,我们可以使用 Vue Test Utils ,提供的mount/shallowMount 来代替Vue.extend,它用于安装和渲染我们的组件。我们将组件的属性传递给 mount 函数。另外,我们使用 wrapper 查询组件结构,并确保其 HTML 内容包含传递的 msg 属性。

describe("HelloWorld.vue", () => {
  it("renders props.msg when passed", () => {
    const msg = "new message";
    const wrapper = shallowMount(HelloWorld, {
      props: { msg }
    });
    expect(wrapper.text()).toMatch(msg);
    expect(wrapper.find("h1").text()).toMatch(msg);
  });
});

测试Todo组件

我们来采用TDD的方式来测试,也就是先编写测试用例
先指定测试的功能: 我们要编写个Todo组件

May-25-2023 12-23-09.gif

  1. 当输入框输入内容时会将数据映射到组件实例上
it("当输入框输入内容时会将数据映射到组件实例上", () => {
    // 1) 渲染Todo组件
    let wrapper = shallowMount(Todo);
    let input = wrapper.find("input");
    // 2.设置value属性 并触发input事件
    input.setValue("hello world");
    // 3.看下数据是否被正确替换
    expect(wrapper.vm.value).toBe("hello world");
  });
  1. 如果输入框为空则不能添加,不为空则新增一条
  it("如果输入框为空则不能添加,不为空则新增一条", async () => {
    let wrapper = shallowMount(Todo);
    let button = wrapper.find("button");
    // 点击按钮新增一条
    wrapper.setData({ value: "" }); // 设置数据为空
    button.trigger("click");
    console.log("len", wrapper.findAll("li").length);
    expect(wrapper.findAll("li").length).toBe(0);
    wrapper.setData({ value: "hello" }); // 写入内容
    await button.trigger("click");
    expect(wrapper.findAll("li").length).toBe(1);
  });
  1. 增加的数据内容为刚才输入的内容
it("增加的数据内容为刚才输入的内容", async () => {
    let wrapper = shallowMount(Todo);
    let input = wrapper.find("input");
    let button = wrapper.find("button");
    input.setValue("hello world");
    button.trigger("click");
    await wrapper.vm.$nextTick();
    expect(wrapper.find("li").text()).toMatch(/hello world/);
  });

根据测试用例,写出代码

<template>
  <div>
    <input type="text" v-model="value" />
    <button @click="addTodo">addTodo</button>
    <ul>
      <li v-for="(todo, index) in todos" :key="index">{{ todo }}</li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "todo",
  methods: {
    addTodo() {
      this.value && this.todos.push(this.value);
    }
  },
  data() {
    return {
      value: "",
      todos: []
    };
  }
};
</script>

使用Jest钩子函数将创建包裹器和移除

describe("测试Todo组件", () => {
let wrapper;
  beforeEach(() => {
    wrapper = shallowMount(Todo);
  });
  afterEach(() => {
    wrapper.unmount();
  });
})

好处

  1. 创建一个 Todo 组件的浅渲染 Wrapper实例,并将其保存为变量wrapper
  2. 在每个测试用例执行前调用 beforeEach 钩子函数,以确保每个测试用例都拥有一个统一的测试环境
  3. 在每个测试用例执行后调用 afterEach 钩子函数,以确保在一个测试用例执行完毕后清除其对应的测试环境

这样做能够避免不同测试用例之间的状态污染及其它副作用,确保测试用例的独立性。

总结

我们可能将这个Todo组件进行拆分,拆分成TodoInput组件和TodoList组件和TodoItem组件,如果采用单元测试的方式,就需要依次测试每个组件(单元测试是以最小单元来测试) 但是单元测试无法保证整个流程是可以跑通的,所以我们在单元测试的基础上还要采用集成测试

单元测试可以保证测试覆盖率高,但是相对测试代码量大,缺点是无法保证功能正常运行

2.集成测试粒度大,普遍覆盖率低,但是可以保证测试过的功能正常运行

3.一般业务逻辑会采用BDD方式使用集成测试(像测试某个组件的功能是否符合预期)一般工具方法会采用TDD的方式使用单元测试

4.对于 UI 组件来说,我们不推荐一味追求行级覆盖率,因为它会导致我们过分关注组件的内部实现细节,从而导致琐碎的测试

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

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

相关文章

行业报告 | 工业机器视觉深度报告——兼具高成长和成熟技术的AI应用赛道

原创 | 文 BFT机器人 01 核心要点 核心观点: 工业机器视觉是高技术壁垒、商业模式成熟、国产替代迅速、行业快速发展的优秀赛道。行业端&#xff1a;3C电子是最主要的行业&#xff0c;新能源行业增速最快&#xff0c;受益于质量管控政策和行业高增速。技术端&#xff1a;大模型…

让工作效率提升10倍:十大AIGC工具评测

AI技术的普及已经在近年来不断增长。这种技术已经改变了我们与电脑的互动方式&#xff0c;让我们能够更高效、更自然地完成任务。本文将展示10个基于ChatGPT和GPT-3 AI模型构建的最强大的资源&#xff0c;使您更容易充分利用它们的潜力。因此&#xff0c;如果您想利用AI技术改进…

DiscoTOC - 自动内容表格

示例 桌面 移动终端 特性 toc table of contents&#xff08;内容列表&#xff09; 通过菜单上面的设置按钮&#xff0c;根据当前内容的状况一键生成 toc 列表Toc 将会一直在页面中尽显显示 —— 滚动内容与 topic 的链接是同步的当你滚动过当前页面中中的主题的时候&#…

Python numpy - 数组的创建与访问

目录 一 数组array的创建途径 1 列表list 2 函数array 3 函数arange 4 函数zeros 5 函数eyes 6 随机函数randn/ randint 二 数组array的访问 1 访问形状/元素个数/数据类型 2 访问一维数组的位置/范围 3 访问二维数组的位置/范围 4 用&#xff1a;访问二维数组的…

美国餐饮连锁集团【CAVA Group】申请纽交所IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;来自美国的餐饮连锁集团【CAVA Group】近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纽交所IPO上市&#xff0c;股票代码为(CAVA) &#xff0c;CAVA Group…

基于SSM的疫情物资管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

公民开发者学习无代码编程,从CRUD开始

目录 1 创建数据表2 创建新增页面3 新增功能开发4 预览总结 自从Forrester2014年提出低代码的概念后&#xff0c;对于编程人员重新进行了划分。使用传统开发工具&#xff0c;使用代码进行编程的叫专业开发人员。使用低代码或者无代码开发工具&#xff0c;作为企业内部的人员&am…

基于深度学习的高精度老鼠检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度老鼠检测识别系统可用于日常生活中检测与定位老鼠目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的老鼠目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型训练数据…

如何确定bug是前端还是后端的错误?

前言&#xff1a;学会分析一个bug属于前端还是后端的错误&#xff0c;可方便开发快速定位问题&#xff0c;缩短与开发的沟通成本&#xff0c;也是测试人员的必备技能&#xff0c;笔者面试时就曾经被问到过&#xff0c;那就一起分析一波吧。 一、定义bug类型&#xff1a; 1、…

app渗透-抓包

app渗透-1 前言1.模拟器2.抓包工具-Fiddler2.1抓app包2.1.1设置模拟器2.1.2设置fiddler2.1.3使用 2.2抓小程序2.2.1抓包2.2.2解决抓不到https2.2.3解决抓不到包-12.2.4解决抓不到包-22.2.5解决抓不到包-3 前言 不要把app和小程序想的多困难&#xff0c;其实就是一个小的网站塞…

2023-06-01:讲一讲Redis常见数据结构以及使用场景。

2023-06-01&#xff1a;讲一讲Redis常见数据结构以及使用场景。 答案2023-06-01&#xff1a; 字符串&#xff08;String&#xff09; 适合场景 缓存功能 Redis 作为缓存层&#xff0c;MySQL 作为存储层&#xff0c;在大部分请求中&#xff0c;数据的读取通常是从 Redis 中…

Python笔记(更新ing)

目录 第一章 Python初识1、什么是编程语言2、第一个Python程序 第二章 基本语法1、 字面量2、 注释3、 变量4、 数据类型5、 数据类型转换6、 标识符7、 运算符8、 字符串扩展9、 字符串拼接10、 字符串格式化11、 字符串格式化的精度控制12、 字符串格式化的方式二13、 对表达…

deepin安装docker和pytorch

title: deepin安装docker和pytorch date: 2023-06-01 17:28:58 tags: [linux, torch,docker] deepin安装docker和pytorch 总体的流程图大致如下&#xff0c;首先是安装linux&#xff0c;这个直接跳过&#xff0c;接下来就是安装docker&#xff0c;之后&#xff0c;安装docker之…

推动科技教育普惠|2023 开放原子全球开源峰会校源行分论坛即将启幕

科技创新&#xff0c;人才先行&#xff0c;高校作为开源人才培养的主阵地&#xff0c;在开源的发展中扮演着关键角色。 6 月 13 日&#xff0c;2023 开放原子全球开源峰会校源行分论坛将在北京经开区亦创国际会展中心盛大举行。论坛以“聚缘于校、开源共行”为主题&#xff0c;…

上海亚商投顾:沪指冲高回落微涨 AI应用端再度爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日冲高回落&#xff0c;创业板指相对偏强。AI应用端再度爆发&#xff0c;传媒、影视、游戏等方向领涨&a…

『Linux』第九讲:Linux多线程详解(四)_ 生产者消费者模型

「前言」文章是关于Linux多线程方面的知识&#xff0c;上一篇是 Linux多线程详解&#xff08;三&#xff09;&#xff0c;今天这篇是 Linux多线程详解&#xff08;四&#xff09;&#xff0c;内容大致是生产消费者模型&#xff0c;讲解下面开始&#xff01; 「归属专栏」Linux系…

实用调试技巧与案例分析

目录 调试(Debug)&#xff1a; 调试的基本步骤&#xff1a; Debug和Release的介绍&#xff1a; 几个常用的快捷键&#xff1a; 案例一&#xff1a; 案例二&#xff1a; 如何写出好(易于调试)的代码&#xff1f; 案例一&#xff1a; 1.assert用法 2.const用法 案例二…

离散数学-数理逻辑

《离散数学》是计算机专业的一门十分重要的专业基础课。离散数学作为有力的数学工具对计算机的发展、计算机研究起着重大的作用。目前&#xff0c;计算机科学中普通采用离散数学中的一些基本概念、基本思想和基本方法。通过本课程的学习&#xff0c;掌握数理逻辑、集合论、代数…

6月1号软件资讯更新合集......

Chrome 114 正式发布&#xff0c;支持 CHIPS 自 Chrome 113 发布以来&#xff0c;已经过了四个星期&#xff0c;Google 近日也准时发布了 Chrome 114。Chrome 114 默认启用了 CHIPS&#xff0c;这是 Google 通过新的 cookie 属性来淘汰第三方 Cookie 的一部分&#xff1b;Chro…

利用Git及GitHub对项目进行版本控制

目录 一、在本地安装Git 二、利用Git将项目上传到Github上 三、用HTTPS获取GitHub上的项目 四、版本控制 一、在本地安装Git 1、Git安装链接&#xff1a;https://git-scm.com/downloads 2、下载安装包&#xff0c;双击exe文件进行安装&#xff1a; 3、接下来会弹出一系列…