Angular 2/4/6/7-使用路由器进行单元测试


76

在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) {}

Answers:


150

您也可以只使用RouterTestingModule并像这样监视导航功能...

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);

    });

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

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

10
谢谢,这有效!我也用router = TestBed.get(Router)我的路由器保存到夹具旁边一个变量,而不是铸造部件的任何作为推荐angular.io/guide/testing#testbedget
瑞安伯比奇

1
谢谢,这解决了我的问题:模拟路由器时无法读取未定义的属性“ root”。
朱尼·布鲁萨斯

嗨@ Lenny您能解释一下什么是component.goSomewhere(); 在这里做什么?
严厉的

2
@harsh要通过此测试,组件必须有一个名为的方法goSomewhere(),其中包含代码this.router.navigate([/expectedUrl'])(该代码将导航至/expectedUrl。)
Lenny

通过此代码,我看到以下警告: console.warn ../../../node_modules/@angular/core/bundles/core.umd.js:27337 Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?
Adrisons

32

这是因为Route预期将某些依赖项传递给其构造函数。

如果您使用的是Angular组件,则不应尝试进行隔离测试。您应该使用Angular测试基础结构来准备测试环境。这意味着让Angular创建组件,让它注入所有必需的依赖关系,而不是尝试创建所有组件。

要开始使用,您应该有类似

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']);
  });
});

或类似的东西。您可以使用TestBed从头开始配置模块进行测试。使用进行配置的方式几乎相同@NgModule

在这里,我们只是嘲笑路由器。由于我们只是单元测试,因此我们可能不需要真正的路由功能。我们只想确保使用正确的参数调用它。模拟和间谍将能够为我们捕获该呼叫。

如果确实要使用真实路由器,则需要使用RouterTestingModule,您可以在其中配置路由。在此处此处查看示例

也可以看看:


2

如果我们在组件控制器中注入Route服务,这里就是一个例子:

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();
  }));
});

我们还可以测试其他功能,例如navigate()。以防万一:

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);
      });
}));

我的文件包含所有模拟组件(mock.components.specs.ts)

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

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

export class DummyHomeComponent { }

2

茉莉花可以更好地利用间谍物品。

describe('Test using router', () => {
    const router = jasmine.createSpyObj('Router', ['navigate']);
    ...
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            providers: [  { provide: Router, useValue: router } ],
            ...
    });        
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.