在 Angular 中,我如何为实现这样的
CanActivateFn
的东西编写单元测试用例?
export const AuthorizedUserClaimGuard: CanActivateFn = (route, state) => {
const auth = inject(AuthenticationService);
const config = inject(ConfigurationService);
if (!auth.authenticated) {
auth.setState({
route: state.url,
});
auth.logout();
// tslint:disable-next-line: no-console
console.info('User is not authenticated, redirecting to the login page.');
}
const userClaims = config.authorizedClaims;
for (const userClaim of userClaims) {
if (auth.hasPermission(userClaim)) {
return true;
}
}
return false;
};
我尝试了以下代码,但它不起作用,因为
AuthorizedUserClaimGuard
不是一个类。有没有办法让它像这样工作?
describe('AuthorizedUserClaimGuard', () => {
let guard: AuthorizedUserClaimGuard;
let authentication: AuthenticationService;
let configuration: ConfigurationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{
provide: AuthenticationService,
useClass: MockAuthenticationService,
},
],
}).compileComponents();
}));
beforeEach(() => {
authentication = TestBed.get(AuthenticationService);
configuration = TestBed.get(ConfigurationService);
configuration.setConfiguration(MOCK_CONFIGURATION);
guard = new AuthorizedUserClaimGuard(authentication, configuration);
});
it('should return true for a logged in user', () => {
const route = createMockRoute();
const state = createMockRouteState();
expect(guard.canActivate(route, state)).toBeTruthy();
});
}
您必须使用
TestBed.runInInjectionContext
来执行该函数,这样 inject
才能工作。
const result = await TestBed.runInInjectionContext(() =>
AuthorizedUserClaimGuard(route, state));
import {
TestBed,
} from '@angular/core/testing';
import {AuthorizedUserClaimGuard,
AuthenticationService,
ConfigurationService} from './guard';
import { HttpClientTestingModule } from '@angular/common/http/testing';
describe('AuthorizedUserClaimGuard', () => {
let guard: any;
let authentication: AuthenticationService;
let configuration: ConfigurationService;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
],
}).compileComponents();
});
beforeEach(() => {
authentication = TestBed.inject(AuthenticationService);
configuration = TestBed.inject(ConfigurationService);
configuration.setConfiguration({});
});
it('should call logout when not authenticated and return false', async () => {
spyOn(authentication, 'logout');
const route: any = {};
const state: any = {};
const result = await TestBed.runInInjectionContext(() => AuthorizedUserClaimGuard(route, state));
expect(authentication.logout).toHaveBeenCalled();
expect(result).toBe(false);
});
it('should call true when permissions present', async () => {
authentication.authenticated = true;
configuration.authorizedClaims = [{}];
const route: any = {};
const state: any = {};
const result = await TestBed.runInInjectionContext(() => AuthorizedUserClaimGuard(route, state));
expect(result).toBe(true);
});
});
是的,它不是一个类,它是一个函数。你不需要声明它。但是,由于您包含注入,因此您需要在注入上下文中运行您的函数。
describe('AuthorizedUserClaimGuard', () => {
let authentication: AuthenticationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{
provide: AuthenticationService,
useClass: MockAuthenticationService,
},
],
});
}));
it('should return true for a logged in user', () => {
const guardResult = TestBed.runInInjectionContext(() = AuthorizedUserClaimGuard(createMockRoute(), createMockRouteState()));
expect(guardResult).toBeTruthy();
});
}
guardResult 类型可能因您的实现而异。您有同步结果,可以直接比较。之前的回答中的纳伦·穆拉里 (Naren Murali) 预计结果将是一个承诺。如果这是一个可观察的结果,我建议将结果与弹珠进行比较。
使用
TestBed.runInInjectionContext()
是关键(如其他答案中指出的),但这里有一个解决方案,它看起来更像您当前的测试设置,并且可以在多个测试用例中重复使用:
describe('AuthorizedUserClaimGuard', () => {
let guard: CanActivateFn;
let authentication: AuthenticationService;
let configuration: ConfigurationService;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
{
provide: AuthenticationService,
useClass: MockAuthenticationService,
},
],
}).compileComponents();
}));
beforeEach(() => {
authentication = TestBed.get(AuthenticationService);
configuration = TestBed.get(ConfigurationService);
configuration.setConfiguration(MOCK_CONFIGURATION);
guard = (...params) => TestBed.runInInjectionContext(() =>
AuthorizedUserClaimGuard(...params));
});
it('should return true for a logged in user', () => {
const route = createMockRoute();
const state = createMockRouteState();
expect(guard(route, state)).toBeTruthy();
});
}