結論
usevalueでParamMapを返すスタブを作る。
環境
> 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
部分は削除している。
hero-detail.component.html
<div *ngIf="hero">
<h2>{{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>
name:{{hero.name}}
</div>
</div>
hero-detail.component.ts
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);
}
}
hero-detail.component.spec.ts
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)
修正箇所
hero-detail.component.spec.ts
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();
});
});
-
ActivatedRoute
のスタブを生成する -
useValue
プロパティにて、snapshot
の戻り値を設定
-
ParamMap
オブジェクトはconvertToParamMap
メソッドで作成すると便利
修正後
※既存のプロジェクトに生やしたコンポーネントなので、テスト数が違うのはご容赦ください。
>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