65.9K
CodeProject 正在变化。 阅读更多。
Home

Angular 5 中的持续测试组件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2018 年 1 月 26 日

CPOL

7分钟阅读

viewsIcon

20084

Angular 5 中持续测试组件。

就像它的前身一样,Angular 5 在开发时就考虑到了可测试性。Angular 和使用 Angular CLI 创建的项目开箱即用地支持两种不同类型的测试。它们是:

  1. 使用 Jasmine 和 Karma 进行单元测试
  2. 使用 Protractor 进行功能测试(端到端测试)

两者之间的区别在于,单元测试用于独立测试组件和服务的逻辑,而端到端测试则通过在浏览器上模拟用户交互来确保应用程序的功能性。

在本教程中,我将向您介绍 Angular 中用于编写单元测试的两个流行框架——Karma 和 Jasmine。

使用 Karma 和 Jasmine 在 Angular 中进行单元测试

Jasmine 是一个开源的、行为驱动的测试框架,而 Karma 是一个测试运行器,它为持续测试您的应用程序设置了环境。Angular 不乏用于单元测试应用程序的替代方案,例如 Jest 或 Mocha。例如,Jest 经过优化,性能优于 Karma。然而,除非您正在运行一个非常大的应用程序,否则性能优势不会很明显。Jasmine 和 Karma 的文档很完善,因为它们得到了 Angular 团队的官方支持。

除了 Karma 和 Jasmine,Angular 还有一个库可以为您的应用程序创建测试环境。这个库,通常被称为 Angular 测试工具,包含用于 TestBedComponentFixtures 等类的 API 以及用于运行异步测试的其他辅助函数。

让我们开始吧。

配置 Jasmine 和 Karma

如果您还没有创建新项目,请创建一个。这是一个新创建的 Angular 5 项目的目录结构。

.
+-- e2e
¦   +-- app.e2e-spec.ts
¦   +-- app.po.ts
¦   +-- tsconfig.e2e.json
+-- karma.conf.js
+-- package.json
+-- package-lock.json
+-- protractor.conf.js
+-- README.md
+-- src
¦   +-- app
¦   ¦   +-- app.component.css
¦   ¦   +-- app.component.html
¦   ¦   +-- app.component.spec.ts
¦   ¦   +-- app.component.ts
¦   ¦   +-- app.module.ts
¦   +-- assets
¦   +-- environments
¦   ¦   +-- environment.prod.ts
¦   ¦   +-- environment.ts
¦   +-- favicon.ico
¦   +-- index.html
¦   +-- main.ts
¦   +-- polyfills.ts
¦   +-- styles.css
¦   +-- test.ts
¦   +-- tsconfig.app.json
¦   +-- tsconfig.spec.json
¦   +-- typings.d.ts
+-- tsconfig.json
+-- tslint.json

如果您要运行端到端测试,您应该查看 e2e 目录。对于单元测试,每个组件都会生成一个 .spec.ts 文件,类似于 app.component.spec.ts。Jasmine 测试称为规范,所有测试规范都应位于 src/app 目录中。

作为最佳实践,我建议将规范文件靠近其原始组件。这有助于您在应用程序增长时跟踪事物。例如,当您有数百个组件时,管理规范可能会失控。您可以通过多种方式组织测试和组件,但这超出了本教程的范围。

您应该注意的另一个文件是 karma.conf.js。Karma 测试运行器使用它来配置它如何运行测试以及许多其他事情。让我们看看它。

// Karma configuration file, see link for more information
// https://karma.node.org.cn/1.0/config/configuration-file.html

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular/cli'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage-istanbul-reporter'),
      require('@angular/cli/plugins/karma')
    ],
    client:{
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    coverageIstanbulReporter: {
      reports: [ 'html', 'lcovonly' ],
      fixWebpackSourcePaths: true
    },
    angularCli: {
      environment: 'dev'
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false
  });
};

尽管 Chrome 是执行测试的默认浏览器,但我更喜欢在无头版本的 Chrome 上运行测试。这样更快,您可以在终端中完成所有操作。要使用 Chrome Headless,您可能需要先安装 Puppeteer 库。

$ npm install puppeteer --save-dev

现在将 ChromeHeadless 添加到 Karma 配置中。

// karma.conf.js

process.env.CHROME_BIN = require('puppeteer').executablePath()

module.exports = function(config) {
  config.set({
    browsers: ['ChromeHeadless']
  })
}

您还可以使用此空间将您的应用程序与第三方工具连接起来,例如用于自动化测试的 Sealights用于持续集成的 Jenkins

在 Karma 中设置代码覆盖率报告

代码覆盖率测试描述了您的单元测试对代码库的测试程度。代码覆盖率衡量了在执行测试时执行的源代码的程度。更高的代码覆盖率百分比意味着您几乎涵盖了 Angular 项目的所有部分。Karma 有一个使用 Istanbul 生成代码覆盖率报告的插件。

要设置代码覆盖率报告,请按照以下步骤操作:

  1. 安装 karma-coverage 插件。
    npm install karma-coverage --save-dev
    
  2. 将模块添加到 karma.config.js 中的插件列表。
    plugins: [
    ...
    require('karma-coverage')
    ],
  3. 将要测试的文件包含到 preprocessor 对象中。由于我们主要测试组件的源代码,我将只包含那些必要的文件。
      preprocessors: {
      // source files, that you wanna generate coverage for
      // do not include tests or libraries
      // (these files will be instrumented by Istanbul)
      'src/**/*.ts': ['coverage']
    },
  4. 将“coverage”添加到 reporters 数组中。
    reporters: ['progress', 'kjhtml', 'coverage'],
    
  5. 要生成代码覆盖率报告,请运行以下命令:
    ng test --watch=false --code-coverage

将创建一个名为 coverage/ 的新目录,其中包含一个 index.html 文件。在浏览器中打开它,您将找到应用程序的覆盖率报告。

Generating Code coverage reports using Karma

有关代码覆盖率指标的更多详细信息,请参阅本文

测试 Angular 组件——基础知识

创建一个新组件并添加类似这样的内容:

import { Component } from '@angular/core';
@Component({
  selector: 'app-demo',
  template: '<h1>{{title}}</h1>'
})
export classDemoComponent {
  title = 'Testing Demo';
}

DemoComponent 的相应测试应放入 demo.component.spec.ts 中。

以下是测试套件需要做的事情:

  1. 加载组件。
  2. 检查模板是否有一个 h1
  3. 验证 title 属性是否进入模板。

使用 Jasmine 框架描述测试规范

每个测试套件都有一个 describe 块,用于测试应用程序的特定部分。您可以使用第一个参数为测试套件提供一个有意义的 title。第二个参数接受一个函数,这是我们要运行的实际测试。

describe('DemoComponent', () => {
// To be implemented
});

您可以将 describe 块嵌套在彼此内部。这有助于您将应用程序划分为更小的单元,每个单元都有自己的 describe 块。

describe('DemoComponent', () => {
  describe('Header'), () => {
  });

  describe('Footer'), () => {
  });
});

但实际测试是在 it 块内部执行的。

describe('DemoComponent', () => {
   it('should be true', () => {
     expect(true).toBeTruthy();
   });
 }

我们使用了一个期望函数来匹配两个值。expect() 函数接受一个名为实际值的参数,然后链接到某个匹配器函数。虽然这可能现在没有多大意义,但如果我们能做这样的事情会不会很有用呢?

it('should have a title', () => {
expect(component.title).toBeTruthy();
});

还有一个您应该知道的全局函数叫做 beforeEach()。想象一下,在一个单独的 describe 函数中有多个 it() 块。如果您需要在每个测试之前配置一些东西,您可以使用 beforeEach() 方法。

describe('DemoComponent', () => {
    
    beforeEach( () => {
       /* Before Each block */
     });
   
    it('should have a title'), () => {
    
    });
    
    it('should have the text'), () => {
    
    });
});

这有助于消除重复代码,因为 beforeEach 在每个测试执行之前都会调用。还有一个函数叫做 afterEach,它在特定测试执行之后执行。

现在,测试规范即使对于没有测试背景的人来说也易于阅读和理解。此处描述的结构和语法是 Jasmine 测试框架的一部分。您可以查阅其文档以更好地理解 Jasmine 框架。

Angular 测试工具

接下来,我们需要测试 DemoComponent。显而易见的问题是,我们如何与 Angular 环境交互?为了简化事情,Angular 提供了一个测试工具库,其中包含一些有用的类和函数。您可以利用此库的功能为测试套件模拟 Angular 环境。

从测试工具库导入必需品。

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

TestBed 为您的 Angular 应用程序创建了一个测试环境。换句话说,您可以创建一个 NgModule 类并配置它以模拟我们需要测试的实际 AppModuleTestBed 有一个 configureTestingModule 方法,它接受一个元数据对象,您可以使用此 metaobject 来声明我们需要测试的组件和其他模块。

   beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ DemoComponent ]
    })
    .compileComponents();
  }));

async() 是我们之前导入的 Angular 测试工具的一部分。我们已将 async() 函数用作 beforeEach() 的参数。async() 函数有助于以异步方式运行代码,以便其中的代码异步运行。compileComponents() 需要从磁盘获取模板和 CSS,这是一项异步活动,这就是我们使用 async() 的原因。

现在我们需要从 TestBed 中提取 DemoComponent 的实例,以便我们可以在测试中使用它。要获取组件实例,您可以使用 TestBed.createComponent(DemoComponent) 方法。它返回一个组件夹具,您可以使用此夹具访问 component 实例。

 beforeEach(() => {
    fixture = TestBed.createComponent(SignupComponent);
    component = fixture.componentInstance;
    
    /*Debug element */
    de = fixture.debugElement.query(By.css('h1'));
    /* H1 element */
    el = de.nativeElement;
   
    fixture.detectChanges();
  });

由于 TestBed 不会自动触发变更检测,因此只有在运行 fixture.detectChanges() 时,component 属性才会推送到模板中。

现在,添加以下测试以验证以下测试用例:

  • 模板应该有一个标题。
  • 标题应该是 Demo Component。
  • component.title 的更改应该反映在模板中。

这是测试的代码:

it('should have a title', () => {
expect(el).toBeTruthy();
});

it('should display original title', () => {
  fixture.detectChanges();
  expect(el.textContent).toContain(comp.title);
});

it('should display a different test title', () => {
  comp.title = 'Test Title';
  fixture.detectChanges();
  expect(el.textContent).toContain('Test Title');
});

就是这样!如果您做的一切都正确,您的所有测试都应该通过。

摘要

从一开始就测试您的应用程序并持续测试它直到结束,这有助于确保您的代码对于生产是安全的。在本教程中,我向您介绍了使用 Karma 和 Jasmine 在 Angular 中进行测试的基本概念。Karma 是可配置的,您可以更改浏览器,设置自定义代码覆盖率报告以及许多其他事情。最后,我们为演示组件编写了一些测试。

希望您喜欢本教程。请通过评论告诉我您的想法。

Angular 5 中的持续测试组件 - CodeProject - 代码之家
© . All rights reserved.