我如何单元测试一个组件,使用路由器在角度?

在 Angular 2.0.0中,我正在对一个使用路由器的组件进行单元测试。然而,我得到的是‘提供的参数与调用目标的任何签名都不匹配。错误。在 spec.ts 中的 Visual Studio 代码中,红色突出显示的是新的 Router ()

如果有人能告诉我正确的语法,我将不胜感激?先谢谢你。我的代码如下:

眼镜

import { TestBed, async } from '@angular/core/testing';
import { NavToolComponent } from './nav-tool.component';
import { ComponentComm } from '../../shared/component-comm.service';
import { Router } from '@angular/router';


describe('Component: NavTool', () => {
it('should create an instance', () => {
let component = new NavToolComponent( new ComponentComm(), new Router());
expect(component).toBeTruthy();
});
});

组件构造函数

constructor(private componentComm: ComponentComm, private router: Router) {}
127558 次浏览

It's because the Route has some dependencies it expects passed to its constructor.

If you're using Angular components, you shouldn't be trying to do isolated tests. You should use the Angular testing infrastructure to prepare the test environment. This means letting Angular create the component, letting it inject all the required dependencies, instead of you trying to create everything.

To get you started, you should have something like

import { TestBed } from '@angular/core/testing';


describe('Component: NavTool', () => {
let mockRouter = {
navigate: jasmine.createSpy('navigate')
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ NavToolComponent ],
providers: [
{ provide: Router, useValue: mockRouter },
ComponentComm
]
});
});
it('should click link', () => {
let fixture = TestBed.createComponent(NavToolComponent);
fixture.detectChanges();
let component: NavToolComponent = fixture.componentInstance;
component.clickLink('home');
expect(mockRouter.navigate).toHaveBeenCalledWith(['/home']);
});
});

Or something like that. You use the TestBed to configure a module from scratch for the testing. You configure it pretty much the same way with an @NgModule.

Here we are just mocking the router. Since we are just unit testing, we may not want the real routing facility. We just want to make sure that it is called with the right arguments. The mock and spy will be able to capture that call for us.

If you do want to use the real router, then you need to use the RouterTestingModule, where you can configure routes. See an example here and here

See Also:

You can also just use the RouterTestingModule and just spyOn the navigate function like this

import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { Router } from '@angular/router';


import { MyModule } from './my-module';
import { MyComponent } from './my-component';


describe('something', () => {


let fixture: ComponentFixture<LandingComponent>;
let router: Router;


beforeEach(() => {


TestBed.configureTestingModule({
imports: [
MyModule,
RouterTestingModule.withRoutes([]),
],
}).compileComponents();


fixture = TestBed.createComponent(MyComponent);
router = TestBed.get(Router); // TestBed.inject(Router) for Angular 9+


});


it('should navigate', () => {
const component = fixture.componentInstance;
const navigateSpy = spyOn(router, 'navigate');


component.goSomewhere();
expect(navigateSpy).toHaveBeenCalledWith(['/expectedUrl']);
});
});

Jasmine goes one better with full spy objects...

describe('Test using router', () => {
const router = jasmine.createSpyObj('Router', ['navigate']);
...
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [  { provide: Router, useValue: router } ],
...
});
});

Here an axample if we inject Route service in our component controller:

import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing'; // Because we inject service in our component
import { Router } from '@angular/router'; // Just if we need to test Route Service functionality


import { AppComponent } from './app.component';
import { DummyLoginLayoutComponent } from '../../../testing/mock.components.spec'; // Because we inject service in your component


describe('AppComponent', () => {
let router: Router; // Just if we need to test Route Service functionality


beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent,
DummyLoginLayoutComponent // Because we inject service in our component
],
imports: [
RouterTestingModule.withRoutes([
{ path: 'login', component: DummyLoginLayoutComponent },
]) // Because we inject service in our component
],
}).compileComponents();


router = TestBed.get(Router); // Just if we need to test Route Service functionality
router.initialNavigation(); // Just if we need to test Route Service functionality
}));


it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
});

We can also test other functionalitites such as navigate(). Just in case:

it('should call eventPage once with /register path if event is instanceof NavigationStart', fakeAsync(() => {
spyOn(analyticService, 'eventPage');
router.navigate(['register'])
.then(() => {
const baseUrl = window.location.origin;
const url = `${baseUrl}/register`;
expect(analyticService.eventPage).toHaveBeenCalledTimes(1);
expect(analyticService.eventPage).toHaveBeenCalledWith(url);
});
}));

My file with all mock components (mock.components.specs.ts)

import { Component } from '@angular/core';


@Component({
selector: 'home',
template: '<div>Dummy home component</div>',
styleUrls: []
})


export class DummyHomeComponent { }