关于前端:跟着华为DevUI开源组件库学写单元测试用例

62次阅读

共计 4726 个字符,预计需要花费 12 分钟才能阅读完成。

DevUI 是一支兼具设计视角和工程视角的团队,服务于华为云 DevCloud 平台和华为外部数个中后盾零碎,服务于设计师和前端工程师。
官方网站:devui.design
Ng 组件库:ng-devui(欢送 Star)
官网交换:增加 DevUI 小助手(devui-official)
DevUIHelper 插件:DevUIHelper-LSP(欢送 Star)

引言

作为一个成熟的 web 前端工程师,咱们都熟知,编写单元测试用例,对前端而言,的确收益不大,业务代码还写不完呢,写什么测试用例呐,大略这是诸多 web 前端工程师的现状。

那么为什么我还要介绍单元测试用例编写呢?

在开发侧发现产品质量问题,对于开发来说,是老本最低的一种保障上线产品质量的办法。

在开发时编写测试用例,就是诸多从开发侧发现问题的策略之一。

在对 devui 组件库进行单元测试用例编写的时候,会思考两点:

  1. 首先开源库曾经有了组件的实现,测试驱动开发的场景比拟弱;
  2. 如果基于开源组件库进行开发应用,咱们仅关怀咱们本人罕用的一些性能是否可能保障。

本文将以组件库中的 Button 组件为例,开展对于 DevUI 开源组件库单元测试用例编写的介绍。

1 编写单元测试用例前的筹备

Step 1: 克隆 ng-devui 源码

先将 ng-devui 组件库源码克隆下来,装置依赖包后保障 npm start 可能启动我的项目:

Step 2: 找到启动单元测试的命令

我的项目启动后,返回 package.json 文件,能够看到有两个 test 命令:

这个时候可能有些读者有点懵逼,这两个命令,我该运行哪个呢?

通过查看 angular.json 查看应该运行的命令,拉到 angular.json 文件底部,能够查看到默认运行的是 devui,我的项目中有三个我的项目:devuidevui-e2edevui-lib

devui 的根门路是src,devui-lib 的根门路是devui,而 DevUI 组件库的所有组件都在 devui 门路之下:

根据上述判断可知,DevUI 组件库的我的项目应该是devui-lib

因而咱们应该运行的 package.json 中的 test:lib 命令:

npm run test:lib

Step 3: 运行单元测试

运行完 npm run test:lib 命令,能够看到 DevUI 组件库蕴含 666 个单元测试用例,其中 5 个跳过,661 个胜利,0 个失败。

2 开始编写 Button 组件的单元测试用例

Step 1: 找到 Button 组件的单元测试文件

关上 button 组件的源码目录,点击进入 button 的测试文件 button.spec.ts,将遇到的第一个 describe 改写成 fdescribe,从新运行npm run test:lib,此时会发现只有 15 个运行胜利的用例,在 button.spec.ts 文件中搜寻 it,会发现有 15 个 it 字段。

实际上,一个 it 即为一个单元测试用例,fdescribe 示意,运行的时候只运行整个 fdescribe 下蕴含的 it 单元测试用例。

Step 2: 布局测试并筹备数据

为了保障文章的不那么冗余,这里只抛砖引玉,仅对 button 的局部性能进行单元测试,理解了单元测试用例运行的根本形式之后,就能够开始着手单元测试用例的编写。

编写前将现有的 button.spec.ts 文件内容删除,以便咱们从 0 开始编写单元测试用例。

编写测试用例时,要先将 button 组件引入,其中,beforeEach 示意每个 it 单元测试用例执行前都会执行的操作。

@Component({
  template: `
    <d-button></d-button>
  `
})
class TestButtonAutoFocusComponent {}

fdescribe('Button', () => {
  let fixture: ComponentFixture<any>;
  beforeEach(async(() => {
    TestBed.configureTestingModule({imports: [ButtonModule],
      declarations: [TestButtonComponent, TestButtonAutoFocusComponent]
    }).compileComponents();}));
  
  ...
});

这里将会对 button 的根本款式,common 款式、按钮点击性能及禁用状态进行测试,因而,咱们会在 TestButtonComponent 测试组件中的 button 上加上款式、是否禁用、点击函数三个性能。

@Component({
  template: `
    <d-button [bsStyle]="style" (btnClick)="isClick()" [disabled]="disabled"></d-button>
  `
})
class TestButtonComponent {
  style = 'primary';
  disabled = false;
  hasClick = false;

  isClick() {this.hasClick = true;}
}

为了测试 button 相干的性能,咱们须要创立一个 TestButtonComponent 的实例,之后还要可能获取到这个实例中应用到的 button 元素,测试时往往会用到四个变量。

let fixture: ComponentFixture<any>;
let testComponent: TestButtonComponent;
let buttonDebug: DebugElement;
let buttonNative: HTMLElement;

beforeEach((() => {fixture = TestBed.createComponent(TestButtonComponent);
  testComponent = fixture.debugElement.componentInstance;
  buttonDebug = fixture.debugElement.query(By.css('d-button'));
  buttonNative = buttonDebug.nativeElement;
  fixture.detectChanges();}));

Step 3: 测试 Button 组件实例创立

为了保障 button 组件没有语法类的致命谬误,首先应该可能保障组件实例可能创立胜利,这也是咱们第一步须要进行的测试。

it('Button demo has created successfully', () => {expect(testComponent).toBeTruthy();});

Step 4: 测试 Button 款式

保障 button 组件的款式,则须要晓得组件可能正确的利用到款式类。

a) 通过查看 button.component.html 文件可知,正确的利用 devui-btn,devui-btn-primary 两个类即可示意 button 可能正确利用到款式类。这样,只有款式文件中的款式类正确,款式就正确。

b) 正确利用 devui-btn,devui-btn-common 两个类即示意 common 类型的 button 款式正确。

it('Button should apply css classes', () => {let buttonHtml = buttonDebug.query(By.css('button'));
  expect(buttonInsideNativeElement.classList.contains('devui-btn')).toBeTruthy();
  expect(buttonInsideNativeElement.classList.contains('devui-btn-primary')).toBeTruthy();
  
  testComponent.style = 'common';
  fixture.detectChanges();
  buttonHtml = buttonDebug.query(By.css('button'));
  
  expect(buttonInsideNativeElement.classList.contains('devui-btn')).toBeTruthy();
  expect(buttonInsideNativeElement.classList.contains('devui-btn-common')).toBeTruthy();});

Step 5: 测试 Button 点击性能

保障 button 性能失常,则须要晓得点击 button 后,是否触发绑定的 isClick 事件,触发 click 事件胜利,则 hasClick 的值将由 false 变更为 true。

a)首先,咱们应该判断一下 hasClick 的初始赋值是否正确;

b)接着,模仿点击 button 按钮所绑定的点击事件。

it('Button click', () => {expect(testComponent.hasClick).toBeFalsy();
  
  let buttonHtml = buttonDebug.query(By.css('button'));
  buttonHtml.nativeElement.click();
  fixture.detectChanges();
  expect(testComponent.hasClick).toBeTruthy();});

Step 6: 测试禁用性能

对于 disabled 状态下,点击有效是其性能上的一大特点,同时 disabled 状态的 button 具备 disabled 属性,所以咱们的单元测试也是分为两个局部:

a)点击生效

b) button 元素具备 disabled 属性

it('Button disabled should have disabled attribute', () => {
  testComponent.disabled = true;
  fixture.detectChanges();

  // 点击生效
  expect(testComponent.hasClick).toBeFalsy();
  let buttonHtml = buttonDebug.query(By.css('button'));
  buttonHtml.nativeElement.click();
  fixture.detectChanges();
  expect(testComponent.hasClick).toBeFalsy();

  // 具备 disabled 款式
  expect(buttonHtml.nativeElement.hasAttribute('disabled')).toBeTruthy();});

3 对品质的敬畏之心

(1)作为前端开发,置信大多数开发都在业务开发中摸爬滚打,如果你遇到的业务对品质要求极高,任何一个重大事故都可能影响到诸多客户,拉低客户的效率,给客户造成损失。这种状况,你该如何保障你的代码品质?

(2)还有一种情景,你开发任何一个小的组件,比方一个小小的按钮,都可能会在几十,上百个业务中应用,你的任何一个失误,都有如落入湖水的石子,荡起整个湖面的涟漪。

以上两种情景,如果开发者没有测试充沛,贸然上线,都会造成重大损失。

稳固:是这两种开发场景第一需要。

这个时候,心愿上述单元测试用例的编写可能对读者有所启发,当然啦,咱们最终的指标仍然是以最小的老本解决更多的问题!

退出咱们

咱们是 DevUI 团队,欢送来这里和咱们一起打造优雅高效的人机设计 / 研发体系。招聘邮箱:muyang2@huawei.com。

文 /DevUI 莫奈的关门弟子

往期文章举荐

《当初开始为你的 Angular 利用编写测试(二)》

《当初开始为你的 Angular 利用编写测试(一)》

《手把手教你搭建一个灰度公布环境》

正文完
 0