编写 Karma-Jasmine 单元测试用例时出现“错误:没有路由器提供程序”
Posted
技术标签:
【中文标题】编写 Karma-Jasmine 单元测试用例时出现“错误:没有路由器提供程序”【英文标题】:"Error: No provider for router" while writing Karma-Jasmine unit test cases 【发布时间】:2017-04-22 11:51:04 【问题描述】:我们已经完成了一个 angular2 项目设置,并在其中创建了一个模块(my-module),并在该模块中使用以下 cmd 命令创建了一个组件(my-new-component):
ng new angular2test
cd angular2test
ng g module my-module
ng generate component my-new-component
创建设置和所有组件后,我们从 angular2test 文件夹中的 cmd 运行 ng test
命令。
以下文件是我们的 my-new-component.component.ts 文件:
import Component, OnInit from '@angular/core';
import Router, Routes, RouterModule from '@angular/router';
import DummyService from '../services/dummy.service';
@Component(
selector: 'app-my-new-component',
templateUrl: './my-new-component.component.html',
styleUrls: ['./my-new-component.component.css']
)
export class MyNewComponentComponent implements OnInit
constructor(private router : Router, private dummyService:DummyService)
ngOnInit()
redirect() : void
//this.router.navigate(['/my-module/my-new-component-1'])
以下文件是我们的 my-new-component.component.spec.ts 文件:
/* tslint:disable:no-unused-variable */
import async, ComponentFixture, TestBed from '@angular/core/testing';
import By from '@angular/platform-browser';
import DebugElement from '@angular/core';
import RouterTestingModule from '@angular/router/testing';
import NgbModule from '@ng-bootstrap/ng-bootstrap';
import DummyService from '../services/dummy.service';
import MyNewComponentComponent from './my-new-component.component';
describe('MyNewComponentComponent', () =>
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [RouterTestingModule, NgbModule.forRoot(), DummyService],
declarations: [ MyNewComponentComponent ]
)
.compileComponents();
));
beforeEach(() =>
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
);
it('should create', () =>
expect(component).toBeTruthy();
);
);
我们在运行 ng test 命令时遇到以下 cmd 错误:
Chrome 54.0.2840 (Windows 7 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (0.593 secs / 2.007 secs)
Chrome 54.0.2840 (Windows 7 0.0.0) MyNewComponentComponent should create FAILED
Failed: Unexpected value 'DummyService' imported by the module 'DynamicTestModule'
Error: Unexpected value 'DummyService' imported by the module 'DynamicTestModule'
我们更新了组件文件和规范文件。很高兴找到下面的代码 sn-p。
以下文件是我们的 my-new-component.component.ts 文件:
import Component, OnInit from '@angular/core';
import Router, Routes, RouterModule from '@angular/router';
import DummyService from '../services/dummy.service';
@Component(
selector: 'app-my-new-component',
templateUrl: './my-new-component.component.html',
styleUrls: ['./my-new-component.component.css']
)
export class MyNewComponentComponent implements OnInit
constructor(private router : Router, private dummyService:DummyService, public fb: FormBuilder)
super(fb);
ngOnInit()
redirect() : void
//this.router.navigate(['/my-module/my-new-component-1'])
以下文件是我们的 my-new-component.component.spec.ts 文件:
/* tslint:disable:no-unused-variable */
import async, ComponentFixture, TestBed from '@angular/core/testing';
import By from '@angular/platform-browser';
import DebugElement from '@angular/core';
import FormsModule, FormGroup, FormBuilder, Validators, ReactiveFormsModule from '@angular/forms';
import SplitPipe from '../../common/pipes/string-split.pipe';
import RouterTestingModule from '@angular/router/testing';
import DummyService from '../services/dummy.service';
import MyNewComponentComponent from './my-new-component.component';
describe('MyNewComponentComponent', () =>
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [RouterTestingModule, DummyService ,HttpModule, FormBuilder],
declarations: [ MyNewComponentComponent, SplitPipe]
)
.compileComponents();
));
beforeEach(() =>
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
);
it('should create', () =>
expect(component).toBeTruthy();
);
);
但是在运行 ng test 命令时,我们得到了以下错误。
09 12 2016 09:13:48.987:WARN [karma]: No captured browser, open http://localhost:9876/
09 12 2016 09:13:49.008:INFO [karma]: Karma v1.2.0 server started at http://localhost:9876/
09 12 2016 09:13:49.010:INFO [launcher]: Launching browser Chrome with unlimited concurrency
09 12 2016 09:13:49.420:INFO [launcher]: Starting browser Chrome
09 12 2016 09:13:58.642:INFO [Chrome 54.0.2840 (Windows 7 0.0.0)]: Connected on socket /#QZ9LSSUVeK6KwNDlAAAA with id 46830907
Failed: Unexpected value 'FormBuilder' imported by the module 'DynamicTestModule'
Error: Unexpected value 'FormBuilder' imported by the module 'DynamicTestModule'
【问题讨论】:
【参考方案1】:我遇到了同样的错误,我想分享我的解决方案以帮助其他人
我在 Karma 中遇到的错误
error properties: Object( ngTempTokenPath: null, ngTokenPath: [ 'RouterModule', 'Router', 'Function', 'Function' ] )
NullInjectorError: R3InjectorError(DynamicTestModule)[RouterModule -> Router -> Function -> Function]:
NullInjectorError: No provider for Function!
inventory-view.component.ts
@Component(
selector: 'app-inventory-view',
templateUrl: './inventory-view.component.html',
styleUrls: ['./inventory-view.component.scss'],
animations: []
)
export class InventoryViewComponent implements OnInit, AfterViewInit, OnDestroy
constructor(
public router: Router, // <--- here was the problem
public activatedRoute: ActivatedRoute
)
在我的测试文件中
inventory-view.component.spec.ts
import HttpClientModule from '@angular/common/http';
import waitForAsync, ComponentFixture, TestBed from '@angular/core/testing';
import RouterTestingModule from '@angular/router/testing';
import ActivatedRoute, convertToParamMap, Router from '@angular/router';
const ActivatedRouteSpy =
snapshot:
paramMap: convertToParamMap(
some: 'some',
else: 'else',
)
,
queryParamMap: of(
convertToParamMap(
some: 'some',
else: 'else',
)
)
;
const RouterSpy = jasmine.createSpyObj(
'Router',
['navigate']
);
describe('InventoryViewComponent', () =>
let component: InventoryViewComponent;
let fixture: ComponentFixture<InventoryViewComponent>;
beforeEach(waitForAsync(() =>
TestBed.configureTestingModule(
imports: [
HttpClientModule,
RouterTestingModule,
],
declarations: [ InventoryViewComponent ],
providers: [
provide: ActivatedRoute, useValue: ActivatedRouteSpy ,
provide: Router, useValue: RouterSpy
]
)
.compileComponents();
));
beforeEach(waitForAsync(() =>
fixture = TestBed.createComponent(InventoryViewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
));
it('should create', () =>
expect(component).toBeTruthy();
);
);
【讨论】:
谢谢,按照您的建议添加 provide: Router, useValue: RouterSpy 解决了我的问题。【参考方案2】:为configureTestingModule testCase添加RouterTestingModule
==> 导入:[RouterTestingModule],
import RouterTestingModule from '@angular/router/testing';
beforeEach(() =>
TestBed.configureTestingModule(
imports: [RouterTestingModule], // <====
providers: [],
declarations: [],
);
);
【讨论】:
在声明中,提供您的组件名称,如下所示:声明:[YourComponentName]【参考方案3】:设置测试模块时需要导入RouterTestingModule。
/* tslint:disable:no-unused-variable */
import async, ComponentFixture, TestBed from '@angular/core/testing';
import By from '@angular/platform-browser';
import DebugElement from '@angular/core';
import RouterTestingModule from '@angular/router/testing';
import MyNewComponentComponent from './my-new-component.component';
describe('MyNewComponentComponent', () =>
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [RouterTestingModule],
declarations: [ MyNewComponentComponent ]
)
.compileComponents();
));
beforeEach(() =>
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
);
it('should create', () =>
expect(component).toBeTruthy();
);
);
编辑:模拟 DummyService 的示例
/* tslint:disable:no-unused-variable */
import async, ComponentFixture, TestBed from '@angular/core/testing';
import By from '@angular/platform-browser';
import DebugElement from '@angular/core';
import RouterTestingModule from '@angular/router/testing';
import MyNewComponentComponent from './my-new-component.component';
// import the service
import DummyService from '../dummy.service';
// mock the service
class MockDummyService extends DummyService
// mock everything used by the component
;
describe('MyNewComponentComponent', () =>
let component: MyNewComponentComponent;
let fixture: ComponentFixture<MyNewComponentComponent>;
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [RouterTestingModule],
declarations: [MyNewComponentComponent],
providers: [
provide: DummyService,
useClass: MockDummyService
]
)
.compileComponents();
));
beforeEach(() =>
fixture = TestBed.createComponent(MyNewComponentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
);
it('should create', () =>
expect(component).toBeTruthy();
);
);
【讨论】:
在没有实现的情况下扩展 DummyService 的 MockDummyService 会不会利用 DummyService 中的相同方法,从而使模拟毫无意义? @JayChase 你可以发布一个 git 链接,例如你创建的或者 stackblitz 链接,它对所有人都有帮助。以上是关于编写 Karma-Jasmine 单元测试用例时出现“错误:没有路由器提供程序”的主要内容,如果未能解决你的问题,请参考以下文章