web-dev-qa-db-ja.com

Angular 2最終リリースルーターユニットテスト

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));
  });

});
28
xphong

テストのために、 TestBed を使用してテストモジュールを作成します。 _TestBed#configureTestingModule_を使用して、_@NgModule_に渡すのと同じ方法でメタデータオブジェクトを渡すことができます。

_beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [ /* modules to import */ ],
    providers: [ /* add providers */ ],
    declarations: [ /* components, directives, and pipes */ ]
  });
});
_

ルーティングでは、通常のRouterModuleを使用する代わりに、 RouterTestingModule を使用します。これにより、RouterLocationが設定されるため、自分で行う必要はありません。 RouterTestingModule.withRoutes(Routes)を呼び出して、ルートを渡すこともできます

_TestBed.configureTestingModule({
  imports: [
    RouterTestingModule.withRoutes([
      { path: 'home', component: DummyComponent }
    ])
  ]
})
_

テストでLocationRouterを取得するには、例のように同じことが機能します。

_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) => {
})));
_

上記のasyncdoneと同様に使用されますが、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はすでにそれを保証しています。

82
Paul Samsotha

useValuerouterStubを使用する代わりに、useClassprovidersを使用できます。

export class RouterStub {
  public url: string = '/';
  constructor() { }
    enter code here
  navigateByUrl(url: any) {
    this.url = url;
  }
}

そしてbeforeEachrouterStubオブジェクトをインスタンス化します

routerStub = new RouterStub()    

そして、テストケースでは

component.router.navigateByUrl('/test');
fixture.detectChanges();
0

Paulによって提案された適切なアプローチ.

そのため、一部のデータをレンダリングするコンポーネントのデータを更新するサービスを追加して、ナビゲーションについて確認できます。

testBed.configureTestingModuleで以下を設定します

providers : [MyService]

次に、foreachでgetサービスを作成します

myService= TestBed.get(MyService);

のようなサービスからいくつかのデータを更新

myService.someMethodCall();

この方法では、データのレンダリングが行われた後に再生できます。

0
Vijay Barot