Angular 2/4/6/7 - Unit Testing mit Router


76

In Angular 2.0.0 teste ich eine Komponente, die Router verwendet. Ich erhalte jedoch die Meldung "Die angegebenen Parameter stimmen nicht mit der Signatur des Anrufziels überein." Error. In Visual Studio-Code in spec.ts ist es der neue Router (), der rot hervorgehoben ist

Ich weiß es wirklich zu schätzen, wenn mir jemand mitteilen könnte, wie die richtige Syntax lauten würde. Danke im Voraus. Mein Code wie folgt:

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

Komponentenkonstruktor

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

Antworten:


150

Sie können auch einfach das RouterTestingModule verwenden und die Navigationsfunktion wie folgt ausspionieren ...

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
Danke, das funktioniert! Ich verwende router = TestBed.get(Router)und speichere meinen Router auch in einer Variablen neben dem Gerät, anstatt eine Komponente in eine beliebige zu gießen
Ryan Burbidge

1
Vielen Dank, dies hat mein Problem gelöst: Ich kann die Eigenschaft 'root' von undefined nicht lesen, wenn ich den Router verspotte.
Juni Brosas

Hi @ Lenny Kannst du bitte erklären, was component.goSomewhere () ist? hier machen?
hart

2
@harsh, um diesen Test zu bestehen, müsste die Komponente eine Methode haben goSomewhere(), die den Code enthält this.router.navigate([/expectedUrl'])(der zu navigieren würde /expectedUrl.
Lenny

Mit diesem Code sehe ich die Warnung: console.warn ../../../node_modules/@angular/core/bundles/core.umd.js:27337 Navigation triggered outside Angular zone, did you forget to call 'ngZone.run()'?
Adrisons

31

Es ist , weil die Routeeinige Abhängigkeiten hat es an den Konstruktor übergeben erwartet.

Wenn Sie Angular-Komponenten verwenden, sollten Sie nicht versuchen, isolierte Tests durchzuführen. Sie sollten die Angular-Testinfrastruktur verwenden, um die Testumgebung vorzubereiten. Dies bedeutet, dass Angular die Komponente erstellen und alle erforderlichen Abhängigkeiten einfügen muss, anstatt zu versuchen, alles zu erstellen.

Um Ihnen den Einstieg zu erleichtern, sollten Sie so etwas wie haben

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

Oder sowas ähnliches. Mit verwenden Sie das TestBed, um ein Modul für den Test von Grund auf neu zu konfigurieren. Sie konfigurieren es so ziemlich genauso mit einem @NgModule.

Hier verspotten wir nur den Router. Da wir nur Unit-Tests durchführen, möchten wir möglicherweise nicht die echte Routing-Funktion. Wir wollen nur sicherstellen, dass es mit den richtigen Argumenten aufgerufen wird. Der Spott und der Spion werden in der Lage sein, diesen Anruf für uns zu erfassen.

Wenn Sie den realen Router verwenden möchten, müssen Sie den verwenden RouterTestingModule, auf dem Sie Routen konfigurieren können. Sehen Sie hier und hier ein Beispiel

Siehe auch:


2

Hier ein Beispiel, wenn wir den Routenservice in unsere Komponentensteuerung einfügen:

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

Wir können auch andere Funktionalitäten wie testen navigate(). Nur für den Fall:

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

Meine Datei mit allen Scheinkomponenten (mock.components.specs.ts)

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

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

export class DummyHomeComponent { }

2

Jasmine geht mit vollen Spionageobjekten besser ...

describe('Test using router', () => {
    const router = jasmine.createSpyObj('Router', ['navigate']);
    ...
    beforeEach(async(() => {
        TestBed.configureTestingModule({
            providers: [  { provide: Router, useValue: router } ],
            ...
    });        
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.