Javascript Angular 2 最终发布路由器单元测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39623722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:44:24  来源:igfitidea点击:

Angular 2 Final Release Router Unit Test

javascriptangularkarma-jasmineangular2-routingangular2-testing

提问by xphong

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

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

Here's what my old unit test looks like in version 2.0.0-beta.14

这是我的旧单元测试在 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));
  });

});

回答by Paul Samsotha

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

为了测试,我们现在使用TestBed. 我们可以使用TestBed#configureTestingModule和 将元数据对象传递给它,就像传递给它一样@NgModule

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

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

对于路由,RouterModule我们不使用普通的,而是使用RouterTestingModule. 这设置了Routerand Location,所以你不需要自己。您还可以通过调用将路由传递给它RouterTestingModule.withRoutes(Routes)

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

To get the Locationand Routerin the test, the same thing works, as in your example.

要在测试中获得LocationRouter,同样的事情也能工作,就像你的例子一样。

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

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

async上述用于像done除了我们并不需要显式调用done。在所有异步任务完成后,Angular 实际上会为我们做这件事。

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

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 navigatemethod. It doesn't need to test that the router works. Angular already guarantees that.

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

回答by karthik kannan B

Instead of using useValuefor routerStub, you can use useClassin the providersand it really worked for me.

您可以使用in而不是使用useValuefor routerStub,它真的对我有用。useClassproviders

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

And in the beforeEachjust instantiate the routerStubobject like

并且在beforeEach刚刚实例化routerStub对象时

routerStub = new RouterStub()    

And in the test cases

在测试用例中

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

回答by Vijay Barot

Good approach suggested by PaulI have also configure my routing same way but additionally I have added service to update some data for routing and then check for current location.

Paul建议的好方法 我也以相同的方式配置了我的路由,但另外我添加了服务来更新一些路由数据,然后检查当前位置。

so you can add service to update data on component which render some data and then will check about navigation.

所以你可以添加服务来更新组件上的数据,这些数据呈现一些数据,然后检查导航。

configure below in TestBed.configureTestingModule

在 TestBed.configureTestingModule 中配置下面

providers : [MyService]

then create get service in foreach

然后在 foreach 中创建 get 服务

myService= TestBed.get(MyService);

update some data from service like

更新来自服务的一些数据,如

myService.someMethodCall();

This way you can play after some data rendering happen.

这样你就可以在一些数据渲染发生后播放。