我正在为Angular 2中的NavBar组件编写单元测试。我对路由器进行了模拟,并且它通过了我的所有测试;但是,我创建了一个服务来为路由设置活动类,这导致我的单元测试因错误而失败:
undefined不是一个对象(评估' this.router.url.substring')
NavActive服务
import { Injectable } from '@angular/core';
import { Router, RouterModule } from '@angular/router';
@Injectable()
export class NavActiveService {
constructor(private router: Router) {
}
homeActive() {
if (this.router.url === '/') {
return '#0fecdb';
}
else {
return '#00f';
}
}
loginActive() {
if (this.router.url.substring(0,6) === '/login') {
return '#0fecdb';
}
else {
return '#00f';
}
}
uploadActive() {
if (this.router.url.substring(0,7) === '/upload') {
return '#0fecdb';
}
else {
return '#00f';
}
}
aboutActive() {
if (this.router.url.substring(0,5) === '/about') {
return '#0fecdb';
}
else {
return '#00f';
}
}
contactActive() {
if (this.router.url.substring(0,7) === '/contact') {
return '#0fecdb';
}
else {
return '#00f';
}
}
four04Active() {
if (this.router.url === '/**') {
return '#0fecdb';
}
else {
return '#00f';
}
}
}
导航栏组件
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { NavActiveService } from '../../../services/navactive.service';
import { GlobalEventsManager } from '../../../services/GlobalEventsManager';
@Component({
moduleId: module.id,
selector: 'my-navbar',
templateUrl: 'navbar.component.html',
styleUrls:['navbar.component.css'],
providers: [NavActiveService]
})
export class NavComponent {
showNavBar: boolean = true;
constructor(private router: Router,
private navactiveservice:NavActiveService,
private globalEventsManager: GlobalEventsManager){
this.globalEventsManager.showNavBar.subscribe((mode:boolean)=>{
this.showNavBar = mode;
});
}
}
Navbar HTML
<div *ngIf="showNavBar">
<nav class="navbar navbar-fixed-top navbar-light bg-faded">
<button class="navbar-toggler hidden-sm-up" type="button" data-toggle="collapse" data-target="#navbar">
☰
</button>
<div class="collapse navbar-toggleable-xs" id="navbar">
<div class="container">
<a class="navbar-brand" [routerLink]="'/'">My App</a>
<ul class="nav navbar-nav navbar-right">
<li class="nav-item" >
<a class="nav-link" [routerLink]="'/'" [style.backgroundColor]="this.navactiveservice.homeActive()" > <i class="fa fa-home"></i> Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item" >
<a class="nav-link" [routerLink]="'/upload'" [style.backgroundColor]="this.navactiveservice.uploadActive()" > <i class="fa fa-upload"></i> Upload </a>
</li>
<li class="nav-item" >
<a class="nav-link" [routerLink]="'/about'" [style.backgroundColor]="this.navactiveservice.aboutActive()" > <i class="fa fa-bar-chart"> </i> Tracking Data</a>
</li>
<li class="nav-item" >
<a class="nav-link" [routerLink]="'/login'" [style.backgroundColor]="this.navactiveservice.loginActive()" > <i class="fa fa-user"></i> Logout</a>
</li>
</ul>
</div>
</div>
</nav>
</div>
Navbar单元测试
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { NavComponent } from './navbar.component';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { RouterLinkStubDirective, RouterOutletStubComponent } from '../../../../test/router-stubs';
import { Router } from '@angular/router';
import { GlobalEventsManager } from '../../../services/GlobalEventsManager';
import { NavActiveService } from '../../../services/navactive.service';
import { RouterModule } from '@angular/router';
import { SharedModule } from '../shared.module';
export function main() {
let comp: NavComponent;
let fixture: ComponentFixture<NavComponent>;
let mockRouter:any;
class MockRouter {
//noinspection TypeScriptUnresolvedFunction
navigate = jasmine.createSpy('navigate');
}
describe('Navbar Componenet', () => {
beforeEach( async(() => {
mockRouter = new MockRouter();
TestBed.configureTestingModule({
imports: [ SharedModule ]
})
// Get rid of app's Router configuration otherwise many failures.
// Doing so removes Router declarations; add the Router stubs
.overrideModule(SharedModule, {
remove: {
imports: [ RouterModule ],
},
add: {
declarations: [ RouterLinkStubDirective, RouterOutletStubComponent ],
providers: [ { provide: Router, useValue: mockRouter }, GlobalEventsManager, NavActiveService ],
}
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(NavComponent);
comp = fixture.componentInstance;
});
}));
tests();
});
function tests() {
let links: RouterLinkStubDirective[];
let linkDes: DebugElement[];
beforeEach(() => {
// trigger initial data binding
fixture.detectChanges();
// find DebugElements with an attached RouterLinkStubDirective
linkDes = fixture.debugElement
.queryAll(By.directive(RouterLinkStubDirective));
// get the attached link directive instances using the DebugElement injectors
links = linkDes
.map(de => de.injector.get(RouterLinkStubDirective) as RouterLinkStubDirective);
});
it('can instantiate it', () => {
expect(comp).not.toBeNull();
});
it('can get RouterLinks from template', () => {
expect(links.length).toBe(5, 'should have 5 links');
expect(links[0].linkParams).toBe( '/', '1st link should go to Home');
expect(links[1].linkParams).toBe('/', '2nd link should go to Home');
});
it('can click upload link in template', () => {
const uploadLinkDe = linkDes[2];
const uploadLink = links[2];
expect(uploadLink.navigatedTo).toBeNull('link should not have navigated yet');
uploadLinkDe.triggerEventHandler('click', null);
fixture.detectChanges();
expect(uploadLink.navigatedTo).toBe('/upload');
});
}
}
我如何模拟navActiveService以便我的测试成功通过?
答案 0 :(得分:1)
在NavActiveService
中,您使用的是this.router.url.substring(0,7)
,但您的Router
存根没有url
属性。它只有一个navigate
函数。
对于每个测试,您可能只想设置url
的值。
mockRouter.url = '/contact'
或者,如果不需要更改测试,只需在声明它时添加它。
class MockRouter {
url = '/';
navigate = jasmine.createSpy('navigate');
}