Angular 2 最终发布路由器单元测试 [英] Angular 2 Final Release Router Unit Test

查看:23
本文介绍了Angular 2 最终发布路由器单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用 karma 和 jasmine 对 Angular 2.0.0 版中的路由器进行单元测试?

How do I unit test routers in Angular version 2.0.0 with karma and jasmine?

这是我在 2.0.0-beta.14 版本中的旧单元测试的样子

Here's what my old unit test looks like in version 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

For testing we now create a testing module using TestBed. We can use the TestBed#configureTestingModule and pass a metadata object to it the same way we would pass to @NgModule

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

对于路由,我们不使用普通的RouterModule,而是使用RouterTestingModule.这将设置 RouterLocation,因此您不需要自己设置.您还可以通过调用 RouterTestingModule.withRoutes(Routes)

For routing, instead of using the normal RouterModule, we would instead use RouterTestingModule. This sets up the Router and Location, so you don't need to yourself. You can also pass routes to it, by calling RouterTestingModule.withRoutes(Routes)

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

要在测试中获取 LocationRouter,与您的示例中的操作相同.

To get the Location and Router in the test, the same thing works, as in your example.

let router, location;

beforeEach(() => {
  TestBed...
});

beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
  router = _router;
  location = _location;
}));

您也可以根据需要注入每个测试

You could also inject into each test as necessary

it('should go home',
    async(inject([Router, Location], (router: Router, location: Location) => {
})));

上面的asyncdone 一样使用,只是我们不需要显式调用done.在所有异步任务完成后,Angular 实际上会为我们做这件事.

The async above is used like done except we don't need to explicitly call done. Angular will actually do that for us after all asynchronous tasks are complete.

另一种获取提供者的方法是从测试平台.

Another way to get the providers is from the test bed.

let location, router;

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [RouterTestingModule.withRoutes([
      { path: 'home', component: DummyComponent }
    ])],
  });
  let injector = getTestBed();
  location = injector.get(Location);
  router = injector.get(Router);
});

这是一个完整的测试,重构您的示例

Here's a complete test, refactoring your example

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

更新

此外,如果您想简单地模拟路由器,这实际上可能是进行单元测试的更好方法,您可以简单地执行

UPDATE

Also, if you want to simply mock the router, which actually might be the better way to go in a unit test, you could simply do

let routerStub;

beforeEach(() => {
  routerStub = {
    navigate: jasmine.createSpy('navigate'),
  };
  TestBed.configureTestingModule({
    providers: [ { provide: Router, useValue: routerStub } ],
  });
});

在您的测试中,您要做的就是测试当组件与其交互时是否使用正确的参数调用了存根

And in your tests, all you want to do is test that the stub is called with the correct argument, when the component interacts with it

expect(routerStub.navigate).toHaveBeenCalledWith(['/route']);

除非您真的想测试一些路由,否则这可能是首选方式.无需设置任何路由.在单元测试中,如果您使用的是真正的路由,则会涉及不必要的副作用,这些副作用可能会影响您真正尝试测试的内容,这只是组件的行为.而组件的行为只是简单地调用navigate 方法.不需要测试路由器是否工作.Angular 已经保证了这一点.

Unless you actually want to test some routing, this is probably the preferred way to go. No need to set up any routing. In a unit test, if you are using real routing, you're involving unnecessary side effects that could affect what you are really trying to test, which is just the behavior of the component. And the behavior of the component is to simply call the navigate method. It doesn't need to test that the router works. Angular already guarantees that.

这篇关于Angular 2 最终发布路由器单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆