简体   繁体   English

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

[英]Angular 2/4/6/7 - Unit Testing with Router

In Angular 2.0.0, I am unit testing a component that uses Router.在 Angular 2.0.0 中,我正在对使用路由器的组件进行单元测试。 However I get the 'Supplied parameters do not match any signature of call target.'但是我得到“提供的参数与调用目标的任何签名不匹配”。 error.错误。 In Visual studio code in spec.ts it is the new Router() that is highlighted in red在 spec.ts 中的 Visual Studio 代码中,新的 Router() 以红色突出显示

I really appreciate if someone could let me know what the correct syntax would be?如果有人能让我知道正确的语法是什么,我真的很感激? Thanks in advance.提前致谢。 My code as follows:我的代码如下:

spec.ts规格

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

Component constructor组件构造器

constructor(private componentComm: ComponentComm, private router: Router) {}

You can also just use the RouterTestingModule and just spyOn the navigate function like this...您也可以只使用 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']);
    });
});

It's because the Route has some dependencies it expects passed to its constructor.这是因为Route有一些它期望传递给它的构造函数的依赖项。

If you're using Angular components, you shouldn't be trying to do isolated tests.如果您使用的是 Angular 组件,则不应尝试进行孤立的测试。 You should use the Angular testing infrastructure to prepare the test environment.您应该使用 Angular 测试基础设施来准备测试环境。 This means letting Angular create the component, letting it inject all the required dependencies, instead of you trying to create everything.这意味着让 Angular 创建组件,让它注入所有必需的依赖项,而不是您尝试创建所有内容。

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.您可以使用TestBed从头开始配置模块以进行测试。 You configure it pretty much the same way with an @NgModule .您可以使用@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.如果您确实想使用真正的路由器,那么您需要使用RouterTestingModule ,您可以在其中配置路由。 See an example here and here在此处此处查看示例

See Also:另见:

Jasmine goes one better with full spy objects... Jasmine 用完整的间谍对象做得更好......

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:如果我们在组件控制器中注入 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();
  }));
});

We can also test other functionalitites such as navigate() .我们还可以测试其他功能,例如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)我的文件包含所有模拟组件(mock.components.specs.ts)

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

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

export class DummyHomeComponent { }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM