Home >Web Front-end >JS Tutorial >Let's talk about unit testing in Angular

Let's talk about unit testing in Angular

青灯夜游
青灯夜游forward
2021-07-26 10:36:362383browse

This article will talk to you about unit testing in Angular, and introduce how to use the unit testing tool (Karma Jasmine) through examples.

Let's talk about unit testing in Angular

I have been doing Angular front-end development for many years, but I have never had the courage to unit test the front-end. The first reason is that the front-end deals with users and is not easy to test. The second reason is that the project Due to time pressure, I don’t have the energy to do unit testing. This also leads to the need for human testing during front-end development once the business changes. It's time-consuming and has no technical content, which directly makes me doubt my life.

I recently had some free time, so I simply studied Angular’s ​​unit testing. Angular actually has its own unit testing tool: Karma Jasmine:

  • Karma: Karma is an automated test management tool for testing JavaScript code. It can monitor file changes and automatically execute tests.
  • Jasmine: A framework for writing Javascript tests.

[Related tutorial recommendation: "angular tutorial"]

The first test case

When created After Angular is applied, the dependencies of Karma and Jasmine have been added to the package.json file:

"karma": "~1.7.1",  
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.0",
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",

Peers who have done back-end testing probably already know the division of labor of these components:

  • karma: Karma core component
  • karma-chrome-launcher: Chrome launcher, the test will be executed on Chrome
  • karma-coverage-istanbul-reporter: coverage report
  • karma-jasmine: Jasmine core component
  • karma-jasmine-html-reporter: Html test report

In the src directory you will see the name: karma.conf.js, Two files of test.ts.

karma.conf.js: Karma’s configuration file, the configurations that need to be focused on are:

  • frameworks: The test framework used, Jasmine

    is used here
  • port: The port used in the test

  • autoWatch: Whether to automatically monitor changes in the test code and automatically execute the test

  • plugins: The plug-ins used in the test, consistent with the package.json file

  • browsers: The browser used to run the test, Chrome is used here, if you need to use other browsers, You need to install the browser launcher through npm and set it up in plugins and here, for example using Safari:

    npm install karma-safari-launcher --save-dev
    
    plugins: [
        require('karma-safari-launcher')
    ]
    browsers: ['Safari'],

test.ts: test entry file, which initializes the test environment and specifies all tests File

In the app directory, you will also find a file named app.component.spec.ts. This is a Jasmine test. The content is as follows:

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
//测试入口,参数为测试名、方法
describe('AppComponent', () => {
  //每个测试用的Setup
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent  
      ],
    }).compileComponents();
  }));

  //测试用例
  it('should create the app', async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));

  it(`should have as title 'test-demo'`, async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    //断言,期望值是否满足要求
    expect(app.title).toEqual('test-demo');
  }));

  it('should render title in a h1 tag', async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;
    //通过querySelector获取页面元素
    expect(compiled.querySelector('h1').textContent).toContain('Welcome to test-demo!');
  }));

  //每个测试用例的TearDown
  afterEach(function() {
    //清除测试数据
  });
});

The above code uses Jasmine syntax, for a more detailed introduction to Jasmine, see JavaScript Unit Testing Framework: A Preliminary Study of Jasmine. I won’t go into details here.

Execute: ng test, you will see the test report of the above file:

Lets talk about unit testing in Angular

In addition, you can click on a test in the test report to execute it individually , the report is as follows:

Lets talk about unit testing in Angular

Fill in the pit

For testing of components such as Pipe, Service, Router, etc., please refer to the Angular documentation, here Focus on the various pitfalls encountered in the test.

No provider ***

During testing, if the component under test requires other third-party components, servcie or pipe, which are not introduced, No provider will appear Error, the solution is very simple, just use imports or provider to introduce it in beforeEach:

beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        //这里声明
      ],
      imports: [
        //这里引入
      ],
      providers: [
        //这里引入
      ],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
    })
      .compileComponents();
  }));

Request timeout

When developing, TimeOut errors often occur in asynchronous requests due to network reasons. The usual solution is to set the upper limit of TimeOut time and provide humanized prompts for TimeOut errors. TimeOut errors will also occur during testing:

Lets talk about unit testing in Angular

The solution is to set the TimeOut time in a test case:

it('#loadBalance for BCT should return real value', async () => {
  jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000000;
  ...
})

or in Set the TimeOut time uniformly in BeforeEach:

describe("my async specs", function() {
    var originalTimeout;
    beforeEach(function() {
      originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
      jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000000;
    });

    ...

    afterEach(function() {
      jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    });
  });

Define the test Environment

Angular default provides different Environment for development and products. For testing , we can also set Environment.

Create environment.test.ts under src/environment and modify the angular.json content:

"architect":{
    "test":{
        ...
        "configurations": {
            "test": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.test.ts"
                }
              ]
            }
          }
    }
}

Modify the package.json file:

"scripts": {
  "test": "ng test --configuration=test",
}

Execute the following command:

npm test
//或者
ng test --configuration=test

When executing a test, the content configured in the environment.test.ts file is used.

Test data rollback

做过Grails开发的伙计应该知道,单元测试、集成测试后,数据库中的测试数据会通过配置文件清除掉。在前端测试中,测试数据需要自行调用清除代码,对于使用LocalStorage、SessionStorage保持的数据亦是如此,方法很简单,在afterEach添加清除代码:

describe("my async specs", function() {
  
  afterEach(function() {
    //在这里清除测试数据
  });
});

与StoryBook的配合

先前我发布了一篇题为《StoryBook实战》的文章,StoryBook也是用来测试组件的,它与Karma+Jasmine有什么区别呢?

二者都能测试的:

  • Pipe

  • Servcie

  • Component

StoryBook不能测、Karma + Jasmine可测试的:

  • Router

  • Component的界面元素属性、Input、Output

Karma + Jasmine不能做的,StoryBook能做的:

  • Component交互测试

  • 组件管理

  • 编写组件文档

从上面可以看出,Storybook进行的是黑盒测试,Karma + Jasmine则注重白盒测试,二者侧重点不同,没有谁强谁弱之分,只有扬长避短,利用好各自的优点,方可让前端测试更完美,将前端bug扼杀在开发阶段。

一些前端测试感悟

虽然前端开发的工作比较繁琐,也是客户Challenge最多的地方,但是不代表前端只有页面,没有架构。以前之所以觉得Angular的单元测试难做,就是觉得都是页面的东西怎么测?其实,终其原因,还是没有架构,所有的代码都集中在Component中,为了赶进度,通过拷贝、粘贴,怎么快怎么来。结果,悲剧了,后期代码维护困难,一点改动就需要人肉测试。

费时不说,开发人员也没有成长。接触Angular前端测试后,我的脑海里又出现了“测试驱动开发”。一段好代码,前提是要易于测试,不管这段代码是用于前端还是后端。 前端开发人员不仅仅要关注页面的易用性、美观性,同样需要关注前端的架构,一个易于测试的架构才是最好的“武器”。

更多编程相关知识,请访问:编程入门!!

The above is the detailed content of Let's talk about unit testing in Angular. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:掘金--胡伟红. If there is any infringement, please contact admin@php.cn delete