我正在编写我的ng2测试,而且我在测试时将Router注入我的组件时遇到了一些麻烦。我的组件的构造函数只接受一个参数 - private router: Router
。
但是,当我运行我的测试用例时,我在尝试注入路由器时遇到错误。我究竟做错了什么?任何人都可以提供一个有效的例子吗?
我使用angular2-RC.1
这是我得到的错误:
No provider for ComponentResolver! (Router -> ComponentResolver)
这是我的测试:
import {describe, it, expect, beforeEach, afterEach, beforeEachProviders, inject} from "@angular/core/testing";
import {ReflectiveInjector, provide} from "@angular/core";
import {HTTP_PROVIDERS} from "@angular/http";
import {Router, ROUTER_PROVIDERS} from "@angular/router";
import {ROUTER_FAKE_PROVIDERS} from "@angular/router/testing";
import {Location} from "@angular/common";
import {SpyLocation} from "@angular/common/testing/location_mock";
import {Observable} from "rxjs/Observable";
import {MyComp} from "./MyComp";
describe("MyComp", () => {
let injector: ReflectiveInjector,
myComp: MyComp,
router: Router;
beforeEach(() => {
injector = ReflectiveInjector.resolveAndCreate([
HTTP_PROVIDERS,
ROUTER_FAKE_PROVIDERS,
provide(Location, {useClass: SpyLocation})
]);
router = injector.get(Router);
myComp = new MyComp(router);
});
afterEach(() => {
injector = null;
myComp = null;
router = null;
});
it("should be defined", () => {
expect(myComp).toBeDefined();
});
});
答案 0 :(得分:10)
您需要为路由器创建一个jasmine间谍对象。 AppComponent有一个接收路由器的构造函数。
import { AppComponent } from './app.component';
import {Router, ROUTER_PROVIDERS} from "@angular/router";
describe('app component', () => {
let component: AppComponent;
let router: Router;
beforeAll(() => {
router = jasmine.createSpyObj("Router", ['navigate']);
component = new AppComponent(router);
});
it("should be defined", () => {
expect(component).toBeDefined();
});
});
答案 1 :(得分:2)
beforeEach(() => addProviders([
{
provide: Router,
useClass: class { navigate = jasmine.createSpy("navigate"); }
}]));
答案 2 :(得分:1)
一些修改......这个简单的解决方案对我有用:
import {MyComp} from "./MyComp";
import {RootRouter} from 'angular2/src/router/router';
import {provide} from 'angular2/core';
import {Router} from 'angular2/router';
describe("MyComp", () => {
let myComp: MyComp,
router;
beforeEach(() => {
provide(Router, {useClass: RootRouter})
myComp = new MyComp(router);
})
it("should be defined", () => {
expect(myComp).toBeDefined();
});
});
答案 3 :(得分:0)
好吧,我想出了一个解决方案。它并不理想,但它有效。基本上,我正在创建一个实现我需要的方法的MockRouter
类。
<强> MockRouter:强>
export class MockRouter {
public navigate() {
console.log(“Mock router was called.”);
}
}
现在,在我的测试用例中,我所要做的就是为路由器提供模拟实现:
provide(Router, {useClass: MockRouter})
如果NG2文档显示如何正确地将Router
注入到Jasmine测试用例中,那么真的会很好。嘲弄他们的物体似乎应该是一个不必要的步骤。
(仅供参考,我尝试使用ROUTER_FAKE_PROVIDERS
并仍然遇到上述ComponentResolver
错误
答案 4 :(得分:0)
这是另一种解决方案,但有点冗长 允许我们使用 SpyLocation 来检查路线变化。 首先,我们创建通用测试路由器提供商。
路由器 - 测试 - providers.ts
import { ComponentResolver } from '@angular/core';
import { Type } from '@angular/core/src/facade/lang';
import { SpyLocation } from '@angular/common/testing';
import { Location } from '@angular/common';
import { Router, RouterOutletMap } from '@angular/router';
import { RouteSegment } from '@angular/router/src/segments';
import { RouterUrlSerializer, DefaultRouterUrlSerializer } from '@angular/router/src/router_url_serializer';
/**
* this class provides the means of loading the tested component type
*/
export class FakeRootComponentLoader {
constructor(private rootComponentType: Type) {
this.rootComponentType = rootComponentType;
}
public getRootComponentType = () => {
return this.rootComponentType;
}
}
let routerFactory = function (
fakeRootComponentLoader: FakeRootComponentLoader,
componentResolver: ComponentResolver,
urlSerializer: RouterUrlSerializer,
routerOutletMap: RouterOutletMap,
location: Location): Router
{
let fakeRootComponentType = fakeRootComponentLoader.getRootComponentType();
/**
* _rootComponent should not be null, but it is what in angular2 rc.1 code
* so we replicate the behaviour
*/
return new Router(
null,
fakeRootComponentType,
componentResolver,
urlSerializer,
routerOutletMap,
location);
};
export const ROUTER_TEST_PROVIDERS: any[] = [
{provide: RouterUrlSerializer, useClass: DefaultRouterUrlSerializer},
RouterOutletMap,
{provide: Location, useClass: SpyLocation},
{provide: RouteSegment, useFactory: (r) => r.routeTree.root, deps: [Router]},
{
provide: Router,
useFactory: routerFactory,
deps: [FakeRootComponentLoader, ComponentResolver, RouterUrlSerializer, RouterOutletMap, Location]
}
];
下面提供了相应的茉莉花测试。
navigation.spec.ts
import { Component } from '@angular/core';
import { beforeEach, beforeEachProviders, inject } from '@angular/core/testing';
import { ROUTER_DIRECTIVES, Route, Routes, Router } from '@angular/router';
import { TestComponentBuilder } from '@angular/compiler/testing';
import { Location } from '@angular/common';
import { ROUTER_TEST_PROVIDERS, FakeRootComponentLoader } from './router-test-providers';
/**
* We inject router into the EmptyComponent,
* Due to the way DI works in angular2, if we import the ROUTER_TEST_PROVIDERS,
* and inject the Router, we will get our own implementation of the Router injected.
*/
@Component({selector: 'empty-component', template: `empty`})
@Component({
selector: 'empty-component',
template: `empty`,
directives: [ROUTER_DIRECTIVES]
})
class EmptyComponent {
constructor (private router: Router){ }
public getRouter() {return this.router;}
}
@Component({
selector: 'root-component',
template: `<router-outlet></router-outlet>`,
directives: [ROUTER_DIRECTIVES]
})
@Routes([new Route({path: '/login', component: EmptyComponent})])
class RootComponent { }
describe('navigation', () => {
beforeEachProviders(() => [
{
provide: FakeRootComponentLoader,
useFactory: () => new FakeRootComponentLoader(RootComponent)
},
ROUTER_TEST_PROVIDERS,
EmptyComponent
]);
let location: Location;
let testCb: TestComponentBuilder;
let emptyComp: EmptyComponent;
beforeEach(inject([Location, TestComponentBuilder, EmptyComponent], (loc, tcb, emptyCt) => {
location = loc;
testCb = tcb;
emptyComp = emptyCt;
}));
it('should be defined', () => {
expect(EmptyComponent).toBeDefined();
});
it('Should navigate to login', (done) => {
expect(location.path()).toEqual('');
testCb.createAsync(RootComponent).then(fixture => {
emptyComp.getRouter().navigate(['login']).then(() => {
fixture.detectChanges();
expect(location.path()).toBe('/login');
done();
}).catch(e => done.fail(e));
});
});
});
答案 5 :(得分:0)
经过无数建议无效后: 这是一个在Angular4和Karma中为我工作的解决方案:
这是基于Andriy Tolstoy的回答和阅读Angular手册。
//ToBeTestedComponent.spec.ts
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ToBeTestedComponent],
providers: [
{
provide: Router,
useClass: class { navigate = jasmine.createSpy("navigate"); }
}
]
})
.compileComponents();
}));