Angularバージョン2.0.0でカルマとジャスミンを使用してルーターを単体テストするにはどうすればよいですか?
バージョン2.0.0-beta.14での古いユニットテストは次のとおりです。
import {
it,
inject,
injectAsync,
beforeEach,
beforeEachProviders,
TestComponentBuilder
} from 'angular2/testing';
import { RootRouter } from 'angular2/src/router/router';
import { Location, RouteParams, Router, RouteRegistry, ROUTER_PRIMARY_COMPONENT } from 'angular2/router';
import { SpyLocation } from 'angular2/src/mock/location_mock';
import { provide } from 'angular2/core';
import { App } from './app';
describe('Router', () => {
let location, router;
beforeEachProviders(() => [
RouteRegistry,
provide(Location, {useClass: SpyLocation}),
provide(Router, {useClass: RootRouter}),
provide(ROUTER_PRIMARY_COMPONENT, {useValue: App})
]);
beforeEach(inject([Router, Location], (_router, _location) => {
router = _router;
location = _location;
}));
it('Should be able to navigate to Home', done => {
router.navigate(['Home']).then(() => {
expect(location.path()).toBe('');
done();
}).catch(e => done.fail(e));
});
});
テストのために、 TestBed
を使用してテストモジュールを作成します。 _TestBed#configureTestingModule
_を使用して、_@NgModule
_に渡すのと同じ方法でメタデータオブジェクトを渡すことができます。
_beforeEach(() => {
TestBed.configureTestingModule({
imports: [ /* modules to import */ ],
providers: [ /* add providers */ ],
declarations: [ /* components, directives, and pipes */ ]
});
});
_
ルーティングでは、通常のRouterModule
を使用する代わりに、 RouterTestingModule
を使用します。これにより、Router
とLocation
が設定されるため、自分で行う必要はありません。 RouterTestingModule.withRoutes(Routes)
を呼び出して、ルートを渡すこともできます
_TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])
]
})
_
テストでLocation
とRouter
を取得するには、例のように同じことが機能します。
_let router, location;
beforeEach(() => {
TestBed...
});
beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
router = _router;
location = _location;
}));
_
必要に応じて各テストに注入することもできます
_it('should go home',
async(inject([Router, Location], (router: Router, location: Location) => {
})));
_
上記のasync
はdone
と同様に使用されますが、done
を明示的に呼び出す必要はありません。 Angularは、すべての非同期タスクが完了した後、実際にそれを行います。
プロバイダーを取得する別の方法は、テストベッドからです。
_let location, router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])],
});
let injector = getTestBed();
location = injector.get(Location);
router = injector.get(Router);
});
_
サンプルをリファクタリングする完全なテストを次に示します
_import { Component } from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { fakeAsync, async, inject, TestBed, getTestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
@Component({
template: `
<router-outlet></router-outlet>
`
})
class RoutingComponent { }
@Component({
template: ''
})
class DummyComponent { }
describe('component: RoutingComponent', () => {
let location, router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])],
declarations: [RoutingComponent, DummyComponent]
});
});
beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
location = _location;
router = _router;
}));
it('should go home', async(() => {
let fixture = TestBed.createComponent(RoutingComponent);
fixture.detectChanges();
router.navigate(['/home']).then(() => {
expect(location.path()).toBe('/home');
console.log('after expect');
});
}));
});
_
また、単純にルーターをモックしたい場合は、実際には単体テストに行く方が良いかもしれませんが、単純に
_let routerStub;
beforeEach(() => {
routerStub = {
navigate: jasmine.createSpy('navigate'),
};
TestBed.configureTestingModule({
providers: [ { provide: Router, useValue: routerStub } ],
});
});
_
そして、テストでは、コンポーネントが対話するときにスタブが正しい引数で呼び出されることをテストするだけです
_expect(routerStub.navigate).toHaveBeenCalledWith(['/route']);
_
実際にルーティングをテストする場合を除き、これがおそらく推奨される方法です。ルーティングを設定する必要はありません。単体テストでは、実際のルーティングを使用している場合、実際にテストしようとしていることに影響を与える可能性のある不要な副作用が含まれています。これはコンポーネントの動作にすぎません。コンポーネントの動作は、単にnavigate
メソッドを呼び出すことです。ルーターが動作することをテストする必要はありません。 Angularはすでにそれを保証しています。
useValue
にrouterStub
を使用する代わりに、useClass
でproviders
を使用できます。
export class RouterStub {
public url: string = '/';
constructor() { }
enter code here
navigateByUrl(url: any) {
this.url = url;
}
}
そしてbeforeEach
でrouterStub
オブジェクトをインスタンス化します
routerStub = new RouterStub()
そして、テストケースでは
component.router.navigateByUrl('/test');
fixture.detectChanges();
Paulによって提案された適切なアプローチ.
そのため、一部のデータをレンダリングするコンポーネントのデータを更新するサービスを追加して、ナビゲーションについて確認できます。
testBed.configureTestingModuleで以下を設定します
providers : [MyService]
次に、foreachでgetサービスを作成します
myService= TestBed.get(MyService);
のようなサービスからいくつかのデータを更新
myService.someMethodCall();
この方法では、データのレンダリングが行われた後に再生できます。