Ответ 1
Для тестирования мы теперь создаем модуль тестирования, используя TestBed
. Мы можем использовать его TestBed#configureTestingModule
и передать ему объект метаданных так же, как мы переходим к @NgModule
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ /* modules to import */ ],
providers: [ /* add providers */ ],
declarations: [ /* components, directives, and pipes */ ]
});
});
Для маршрутизации вместо обычного RouterModule
вместо этого мы будем использовать RouterTestingModule
. Это устанавливает Router
и Location
, поэтому вам не нужно самостоятельно. Вы также можете передавать маршруты к нему, вызывая RouterTestingModule.withRoutes(Routes)
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])
]
})
Чтобы получить Location
и Router
в тесте, то же самое работает, как и в вашем примере.
let router, location;
beforeEach(() => {
TestBed...
});
beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
router = _router;
location = _location;
}));
Вы также можете при необходимости вводить в каждый тест
it('should go home',
async(inject([Router, Location], (router: Router, location: Location) => {
})));
async
выше используется как done
, за исключением того, что нам не нужно явно вызывать done
. Angular на самом деле сделает это для нас после завершения асинхронных задач вызова.
Другой способ получить провайдеров - это тестовая кровать.
let location, router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])],
});
let injector = getTestBed();
location = injector.get(Location);
router = injector.get(Router);
});
Здесь полный тест, рефакторинг вашего примера
import { Component } from '@angular/core';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { fakeAsync, async, inject, TestBed, getTestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
@Component({
template: `
<router-outlet></router-outlet>
`
})
class RoutingComponent { }
@Component({
template: ''
})
class DummyComponent { }
describe('component: RoutingComponent', () => {
let location, router;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'home', component: DummyComponent }
])],
declarations: [RoutingComponent, DummyComponent]
});
});
beforeEach(inject([Router, Location], (_router: Router, _location: Location) => {
location = _location;
router = _router;
}));
it('should go home', async(() => {
let fixture = TestBed.createComponent(RoutingComponent);
fixture.detectChanges();
router.navigate(['/home']).then(() => {
expect(location.path()).toBe('/home');
console.log('after expect');
});
}));
});
UPDATE
Кроме того, если вы хотите просто издеваться над маршрутизатором, который на самом деле может быть лучшим способом в unit test, вы могли бы просто сделать
let routerStub;
beforeEach(() => {
routerStub = {
navigate: jasmine.createSpy('navigate'),
};
TestBed.configureTestingModule({
providers: [ { provide: Router, useValue: routerStub } ],
});
});
И в ваших тестах все, что вы хотите сделать, это проверить, что заглушка вызывается с правильным аргументом, когда компонент взаимодействует с ним
expect(routerStub.navigate).toHaveBeenCalledWith(['/route']);
Если вы действительно не хотите протестировать некоторую маршрутизацию, это, вероятно, предпочтительный путь. Не нужно настраивать маршрутизацию. В unit test, если вы используете настоящую маршрутизацию, вы включаете ненужные побочные эффекты, которые могут повлиять на то, что вы действительно пытаетесь протестировать, а это просто поведение компонента. А поведение компонента состоит в том, чтобы просто вызвать метод navigate
. Нет необходимости проверять, работает ли маршрутизатор. Angular уже гарантирует это.