单元测试的最小模拟 angular 路由器和 CanActivate 守卫
Minimal mock for unit testing angular Router and CanActivate guard
import {Router, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree} from '@angular/router';
@Injectable({provideIn: 'root'})
export class FooGuard implements CanActivate {
constructor (private readonly router: Router) {}
canActivate (next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<UrlTree> {
const xxx = myMagic(next); // irrelevant app logic that depends on next url only
return (async () => this.router.parseUrl(xxx));
}
}
试图找到一个没有额外样板页面的测试代码示例。希望每个模拟可以得到接近 5-6 行的代码。需要:
- 模拟
Router
- 模拟
ActivatedSnapshot
看看RouterTestingModule。它不是六行代码解决方案,而是一个非常紧凑的解决方案。我认为这是测试守卫和路线的最佳方式:
import { Component, Injectable } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
import { RouterTestingModule } from '@angular/router/testing';
@Injectable({
providedIn: 'root'
})
export class FooGuard implements CanActivate {
constructor (private readonly router: Router) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): UrlTree {
const url = "some/new/url"; // create an url based on next snapshot
return this.router.parseUrl(url);
}
}
@Component({ template: '' })
export class DummyComponent {}
function setup(): {
router: Router
} {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{ path: 'test', component: DummyComponent, canActivate: [ FooGuard ] },
{ path: 'some/new/url', component: DummyComponent }
])
],
declarations: [
DummyComponent
]
});
return {
router: TestBed.get(Router)
};
}
describe(FooGuard.name, () => {
it('should redirect to a new url', async () => {
const { router } = setup();
await router.navigateByUrl('/test');
expect(router.url).toBe('/some/new/url');
})
});
其实常规的Router.forRoot()
应该也适用于这种情况,但是RouterTestingModule
一定更适合测试。例如最后一个提供 custom Location
实现。
import {Router, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree} from '@angular/router';
@Injectable({provideIn: 'root'})
export class FooGuard implements CanActivate {
constructor (private readonly router: Router) {}
canActivate (next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<UrlTree> {
const xxx = myMagic(next); // irrelevant app logic that depends on next url only
return (async () => this.router.parseUrl(xxx));
}
}
试图找到一个没有额外样板页面的测试代码示例。希望每个模拟可以得到接近 5-6 行的代码。需要:
- 模拟
Router
- 模拟
ActivatedSnapshot
看看RouterTestingModule。它不是六行代码解决方案,而是一个非常紧凑的解决方案。我认为这是测试守卫和路线的最佳方式:
import { Component, Injectable } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
import { RouterTestingModule } from '@angular/router/testing';
@Injectable({
providedIn: 'root'
})
export class FooGuard implements CanActivate {
constructor (private readonly router: Router) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): UrlTree {
const url = "some/new/url"; // create an url based on next snapshot
return this.router.parseUrl(url);
}
}
@Component({ template: '' })
export class DummyComponent {}
function setup(): {
router: Router
} {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([
{ path: 'test', component: DummyComponent, canActivate: [ FooGuard ] },
{ path: 'some/new/url', component: DummyComponent }
])
],
declarations: [
DummyComponent
]
});
return {
router: TestBed.get(Router)
};
}
describe(FooGuard.name, () => {
it('should redirect to a new url', async () => {
const { router } = setup();
await router.navigateByUrl('/test');
expect(router.url).toBe('/some/new/url');
})
});
其实常规的Router.forRoot()
应该也适用于这种情况,但是RouterTestingModule
一定更适合测试。例如最后一个提供 custom Location
实现。