fayeah / blogs

方法论、问题驱动、总结
6 stars 0 forks source link

【UI】如何将单元测试性能提高100% #31

Open fayeah opened 4 years ago

fayeah commented 4 years ago

背景:目前在一个Angular的项目,有1380个测试用例,运行完所有的测试用例需要5分钟左右,这是一个非常漫长的过程,一杯茶的工夫都有了。于是想办法提升unit test的性能。

为什么会慢

首先我的运行环境是:

在优化之前的性能: image

了解TestBed

性能优化之前稍微了解下TestBed,官网给出的解释可查看官网(https://angular.cn/guide/testing),但最关键的是TestBed 会动态创建一个用来模拟 @NgModule 的 Angular 测试模块。也就是说TestBed可以帮助我们模拟创建一个模块,从而让我们可以对组件和服务进行更好的测试。举个例子:

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

去research看看别人如何解决这个性能问题

在利用搜索引擎research一番之后,发现angular提供的TestBed有一个实现会引发性能 上的问题:

import {resetFakeAsyncZone} from './fake_async';
import {TestBed} from './test_bed';
declare var global: any;
const _global = <any>(typeof window === 'undefined' ? global : window);
// Reset the test providers and the fake async zone before each test.
if (_global.beforeEach) {
  _global.beforeEach(() => {
    TestBed.resetTestingModule();
    resetFakeAsyncZone();
  });
}

也就是说,在每个测试用例之前,都会重置所有的module和module factories等等,那么就需要重新编译所有的模块、组件和服务,这就大大地降低了运行测试用例的性能。

如何解决

有一个work around来解决不断重新编译的问题:

export const configureTestSuite = () => {
  const testBedApi: any = getTestBed();
  const originReset = TestBed.resetTestingModule;

  beforeAll(() => {
    TestBed.resetTestingModule();
    TestBed.resetTestingModule = () => TestBed;
  });

  afterEach(() => {
      testBedApi._activeFixtures.forEach((fixture: ComponentFixture<any>) => fixture.destroy());
      testBedApi._instantiated = false;
  });

  afterAll(() => {
      TestBed.resetTestingModule = originReset;
      TestBed.resetTestingModule();
  });
};

当moduleFactory已经存在的话就不需要重新编译了,只需要编译每个测试用例所需要的新的组件或是测试模块。便会大大地提高性能。 下图是优化之后的性能: image

可以看到基本上是100%的提升。

注意的是

其他还可以用来优化的方法

reference: