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
Angular 2 Final Release Router Unit Test
提问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#configureTestingModule
and 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 Router
and Location
, so you don't need to yourself. You can also pass routes to it, by calling RouterTestingModule.withRoutes(Routes)
对于路由,RouterModule
我们不使用普通的,而是使用RouterTestingModule
. 这设置了Router
and Location
,所以你不需要自己。您还可以通过调用将路由传递给它RouterTestingModule.withRoutes(Routes)
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])
]
})
To get the Location
and Router
in the test, the same thing works, as in your example.
要在测试中获得Location
和Router
,同样的事情也能工作,就像你的例子一样。
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 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.
将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 navigate
method. It doesn't need to test that the router works. Angular already guarantees that.
除非你真的想测试一些路由,否则这可能是首选的方法。无需设置任何路由。在单元测试中,如果您使用的是真正的路由,则会涉及不必要的副作用,这些副作用可能会影响您真正尝试测试的内容,这只是组件的行为。而组件的行为就是简单地调用navigate
方法。不需要测试路由器是否工作。Angular 已经保证了这一点。
回答by karthik kannan B
Instead of using useValue
for routerStub
, you can use useClass
in the providers
and it really worked for me.
您可以使用in而不是使用useValue
for routerStub
,它真的对我有用。useClass
providers
export class RouterStub {
public url: string = '/';
constructor() { }
enter code here
navigateByUrl(url: any) {
this.url = url;
}
}
And in the beforeEach
just instantiate the routerStub
object 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.
这样你就可以在一些数据渲染发生后播放。