用Angular6来测试依赖于根参数的组件

结论

创建一个返回ParamMap的usevalue存根。

环境

> ng -v

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 6.1.3
Node: 10.8.0
OS: win32 x64
Angular: 6.1.2
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.7.3
@angular-devkit/build-angular     0.7.3
@angular-devkit/build-optimizer   0.7.3
@angular-devkit/build-webpack     0.7.3
@angular-devkit/core              0.7.3
@angular-devkit/schematics        0.7.3
@angular/cli                      6.1.3
@ngtools/webpack                  6.1.3
@schematics/angular               0.7.3
@schematics/update                0.7.3
rxjs                              6.2.2
typescript                        2.7.2
webpack                           4.9.2

测试目标组件

使用HeroDetailComponent的公式教程。
但是这次的说明不涉及Location和Input部分,已删除。

<div *ngIf="hero">
  <h2>{{hero.name | uppercase}} Details</h2>
  <div><span>id: </span>{{hero.id}}</div>
  <div>
    name:{{hero.name}}
  </div>
</div>
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { Hero } from '../hero';
import { HeroService } from '../hero.service';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.scss']
})
export class HeroDetailComponent implements OnInit {
  hero: Hero;

  constructor(
    private route: ActivatedRoute,
    private heroService: HeroService
  ) { }

  ngOnInit(): void {
    this.getHero();
  }

  getHero(): void {
    const id = +this.route.snapshot.paramMap.get('id');
    this.heroService.getHero(id)
      .subscribe(hero => this.hero = hero);
  }
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { HeroDetailComponent } from './hero-detail.component';

describe('HeroDetailComponent', () => {
  let component: HeroDetailComponent;
  let fixture: ComponentFixture<HeroDetailComponent>;

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

  beforeEach(() => {
    fixture = TestBed.createComponent(HeroDetailComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

前修正

由于hero-detail.component.spec.ts保持着自动生成时的原始状态,所以测试必然失败。

>ng test

~~~~~(中略)~~~~~

Chrome 68.0.3440 (Windows 10 0.0.0) HeroDetailComponent should create FAILED
        Error: StaticInjectorError(DynamicTestModule)[HeroDetailComponent -> ActivatedRoute]:
          StaticInjectorError(Platform: core)[HeroDetailComponent -> ActivatedRoute]:
            NullInjectorError: No provider for ActivatedRoute!
            at NullInjector.get (webpack:///./node_modules/@angular/core/fesm5/core.js?:1359:19)
            at resolveToken (webpack:///./node_modules/@angular/core/fesm5/core.js?:1597:24)
            at tryResolveToken (webpack:///./node_modules/@angular/core/fesm5/core.js?:1541:16)
            at StaticInjector.get (webpack:///./node_modules/@angular/core/fesm5/core.js?:1438:20)
            at resolveToken (webpack:///./node_modules/@angular/core/fesm5/core.js?:1597:24)
            at tryResolveToken (webpack:///./node_modules/@angular/core/fesm5/core.js?:1541:16)
            at StaticInjector.get (webpack:///./node_modules/@angular/core/fesm5/core.js?:1438:20)
            at resolveNgModuleDep (webpack:///./node_modules/@angular/core/fesm5/core.js?:8673:29)
            at NgModuleRef_.get (webpack:///./node_modules/@angular/core/fesm5/core.js?:9361:16)
            at resolveDep (webpack:///./node_modules/@angular/core/fesm5/core.js?:9726:45)
        Expected undefined to be truthy.
            at UserContext.eval (webpack:///./src/app/hero-detail/hero-detail.component.spec.ts?:20:27)
            at ZoneDelegate.invoke (webpack:///./node_modules/zone.js/dist/zone.js?:387:26)
            at ProxyZoneSpec.onInvoke (webpack:///./node_modules/zone.js/dist/zone-testing.js?:287:39)

修改部分

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivatedRoute, convertToParamMap } from '@angular/router';

import { HeroDetailComponent } from './hero-detail.component';

describe('HeroDetailComponent', () => {
  let component: HeroDetailComponent;
  let fixture: ComponentFixture<HeroDetailComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
-      declarations: [HeroDetailComponent]
+      declarations: [HeroDetailComponent],
+      providers: [{
+        provide: ActivatedRoute,
+        useValue: {
+          snapshot: { paramMap: convertToParamMap({ id: 11 }) }
+        }
      }]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HeroDetailComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});
    1. 生成 ActivatedRoute 的桩

使用 useValue 属性设置 snapshot 的返回值

使用 convertToParamMap 方法创建 ParamMap 对象会很方便

修正之后

由于这是一个已有的项目中添加的组件,请谅解测试数量的不同。

>ng test

~~~~~(中略)~~~~~

Chrome 68.0.3440 (Windows 10 0.0.0): Executed 11 of 11 SUCCESS (0.403 secs / 0.374 secs)
TOTAL: 11 SUCCESS
TOTAL: 11 SUCCESS

请提供更多的上下文信息。

    • Angular – Testing

 

    angular – How to unit test a component that depends on parameters from ActivatedRoute?
广告
将在 10 秒后关闭
bannerAds