Кутова 2/4/6/7 - модульне тестування за допомогою маршрутизатора


79

У Angular 2.0.0 я тестую компонент, який використовує маршрутизатор. Однак я отримую "Надані параметри не відповідають жодному підпису цільового виклику." помилка. У коді Visual Studio в 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();
  });
});

Конструктор компонентів

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

Відповіді:


157

Ви також можете просто використовувати 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' undefined при знущанні над маршрутизатором.
Джуні Бросас

Привіт @ Ленні Чи можете ви пояснити, що таке component.goSomewhere (); робити тут?
суворий

2
@harsh, щоб пройти цей тест, компонент повинен мати метод, що називається, goSomewhere()що містить код this.router.navigate([/expectedUrl'])(який буде переходити до /expectedUrl.
Ленні

За цим кодом я бачу попередження: console.warn ../../../node_modules/@angular/core/bundles/core.umd.js:27337 Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?
adrisons

33

Це тому, що 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, де ви можете налаштувати маршрути. Дивіться приклад тут і тут

Дивитися також:


3

Жасмин краще поєднується з повними шпигунськими предметами ...

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

2

Ось приклад, якщо ми вводимо службу маршруту в наш контролер компонентів:

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 { }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.