很抱歉提出这类问题。但是我无法找到关于编写canActivate防护文件测试的任何博客或youtube教程。在官方文件中也没有提到任何内容。
任何帮助将不胜感激。
答案 0 :(得分:29)
因为没有人回答我的问题,所以我粘贴了我的代码片段以供参考,以帮助那些可能会遇到这种情况的人。
<强> sampleLoggedIn.guard.ts 强>
import {Injectable} from '@angular/core';
import {Router, CanActivate} from '@angular/router';
import {StorageService} from '../storage.service';
@Injectable()
export class LoggedInGuard implements CanActivate {
constructor(private router: Router, private storageService: StorageService) {
}
/**Overriding canActivate to guard routes
*
* This method returns true if the user is not logged in
* @returns {boolean}
*/
canActivate() {
if (this.storageService.isLoggedIn) {
return true;
} else {
this.router.navigate(['home']);
return false;
}
}
}
<强> sampleLoggedIn.guard.spec.ts 强>
import {TestBed, async} from '@angular/core/testing';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import {CommonModule} from '@angular/common';
import 'rxjs/Rx';
import 'rxjs/add/observable/throw';
import {Router} from '@angular/router';
import 'rxjs/add/operator/map';
import {LoggedInGuard} from './loggedin.guard';
import {StorageService} from '../storage.service';
import {CookieService} from 'angular2-cookie/core';
describe('Logged in guard should', () => {
let loggedInGuard: LoggedInGuard;
let storageService: StorageService;
let router = {
navigate: jasmine.createSpy('navigate')
};
// async beforeEach
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [FormsModule, CommonModule, HttpModule],
providers: [LoggedInGuard, StorageService, CookieService,
{provide: Router, useValue: router}
]
})
.compileComponents(); // compile template and css
}));
// synchronous beforeEach
beforeEach(() => {
loggedInGuard = TestBed.get(LoggedInGuard);
storageService = TestBed.get(StorageService);
});
it('be able to hit route when user is logged in', () => {
storageService.isLoggedIn = true;
expect(loggedInGuard.canActivate()).toBe(true);
});
it('not be able to hit route when user is not logged in', () => {
storageService.isLoggedIn = false;
expect(loggedInGuard.canActivate()).toBe(false);
});
});
答案 1 :(得分:1)
如果您的 Guard 是异步的,则可以使用异步测试进行测试:
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed, waitForAsync } from '@angular/core/testing';
import { Observable, of } from 'rxjs';
describe('MyGuard', () => {
let guard: MyGuard;
let service: MyAsyncService;
// async beforeEach
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
],
providers: [
MyGuard,
MyAsyncService,
],
});
}));
// synchronous beforeEach
beforeEach(() => {
guard = TestBed.inject(MyGuard);
service = TestBed.inject(MyAsyncService);
});
it('should allow if service reports as allowed', (done) => {
service.canFoo = (): Observable<boolean> => of(true);
guard.canActivate(null, null).subscribe({
next: (allowed: boolean) => {
expect(allowed).toBeTrue();
done();
},
error: err => {
fail(err);
},
});
});
it('should reject if service reports as not allowed', () => {
service.canFoo = (): Observable<boolean> => of(false);
guard.canActivate(null, null).subscribe({
next: (allowed: boolean) => {
expect(allowed).toBeFalse();
done();
},
error: err => {
fail(err);
},
});
});
});
答案 2 :(得分:0)
这个问题已经很老了-但是当我试图立即自己找到一些详细的单元测试文档时,我只是想将自己的方法放在这里。通常,如果我的guard / service / component /中存在依赖项,则我认为这些都应该被嘲笑,而不是真正的服务。由于这些服务不是我们要在警卫的单元测试中测试的内容-我们只想测试警卫。 因此,这是一个通用示例,我将如何执行此操作以使后卫返回可观察的物体:
import { MyGuard } from './path/to/your/guard';
import { TestBed } from '@angular/core/testing';
import { finalize } from 'rxjs/operators';
describe('MyGuard Test', () => {
const createMockRoute = (id: string) => {
return {
params: { id: id }
} as any;
};
const createMockRouteState = () => null;
let guard: MyGuard;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
MyGuard,
]
});
guard = TestBed.get(MyGuard);
});
it('should not be able to activate invalid route', done => {
const route = createMockRoute(null);
const state = createMockRouteState();
const res$ = guard.canActivate(route, state);
res$.pipe(finalize(done)).subscribe(res => expect(res).toBeFalsy());
});
});
这就是我在您的特定情况下所要做的(应与angular 6一起使用,canActivate也应采用2个参数):
import { LoggedInGuard } from './loggedin.guard';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { StorageService } from '../storage.service';
describe('LoggedInGuard', () => {
let guard: LoggedInGuard;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
LoggedInGuard,
{ provide: Router, useClass: { navigate: () => null } },
{ provide: StorageService, useClass: { } }
]
});
guard = TestBed.get(LoggedInGuard);
});
it('should not be able to activate when logged out', () => {
const storageService = TestBed.get(StorageService);
storageService.isLoggedIn = false;
const res = guard.canActivate(null, null);
expect(res).toBeFalsy();
});
it('should be able to activate when logged in', () => {
const storageService = TestBed.get(StorageService);
storageService.isLoggedIn = true;
const res = guard.canActivate(null, null);
expect(res).toBeTruthy();
});
});