Как протестировать Angular2 router.navigate?

Я пропустил сообщения <router-outlet> в других модульных тестах, но, чтобы иметь хороший изолированный пример, я создал AuthGuard, который проверяет, зарегистрирован ли пользователь для определенных действий.

Это код:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    if (!this.authService.isLoggedIn()) {
        this.router.navigate(['/login']);
        return false;
    }
    return true;
}

Теперь я хочу написать unit test для этого.

Вот как я начинаю тест:

beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [
            RouterTestingModule.withRoutes([
                {
                    path: 'login',
                    component: DummyComponent
                }
            ])
        ],
        declarations: [
            DummyComponent
        ],
        providers: [
            AuthGuardService,
            {
                provide: AuthService,
                useClass: MockAuthService
            }
        ]
    });
});

Я создал DummyComponent, который ничего не делает. Теперь мой тест. Представьте, что служба возвращает false и запускает this.router.navigate(['/login']):

it('should not let users pass when not logged in', (): void => {
    expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
});

Это приведет к исключению из раздела "Невозможно найти загрузочную первую розетку". Очевидно, я могу использовать toThrow() вместо toBe(false), но это не похоже на очень разумное решение. Поскольку я тестирую службу здесь, нет шаблона, где я могу поместить тег <router-outlet>. Я мог бы издеваться над маршрутизатором и сделать свою собственную навигационную функцию, но тогда какая точка RouterTestingModule? Возможно, вы даже захотите проверить работу навигации.

Ответ 1

Я мог бы издеваться над маршрутизатором и сделать свою собственную навигационную функцию, но тогда какая точка RouterTestingModule? Возможно, вы даже захотите проверить работу навигации.

Нет реальной точки. Если он всего лишь unit test для защитника auth, то просто макет и шпион по макету, чтобы проверить, что метод navigate был вызван с аргументом login

let router = {
  navigate: jasmine.createSpy('navigate')
}

{ provide: Router, useValue: router }

expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
expect(router.navigate).toHaveBeenCalledWith(['/login']);

Вот как обычно должны записываться модульные тесты. Чтобы попытаться протестировать любую реальную реальную навигацию, это, вероятно, подпадает под общее тестирование.

Ответ 2

Если вы хотите протестировать роутер, не издеваясь над ним, вы можете просто вставить его в свой тест, а затем шпионить непосредственно за методом навигации. .and.stub() сделает так, чтобы вызов ничего не делал.

describe('something that navigates', () => {
    it('should navigate', inject([Router], (router: Router) => {
      spyOn(router, 'navigate').and.stub();
      expect(authGuardService.canActivate(<any>{}, <any>{})).toBe(false);
      expect(router.navigate).toHaveBeenCalledWith(['/login']);
    }));
  });