[英]How to use router.navigateByUrl and router.navigate in Angular
[英]Angular 9 - how to test a service that calls navigateByUrl by mocking the router
我能找到的所有示例仅显示如何测试调用 navigateByUrl 的组件。 我有一项服务可以做到这一点:
@Injectable({
providedIn: 'root'
})
export class BreadcrumbService {
constructor(private router: Router, private activateRoute: ActivatedRoute) {}
/**
* Return a array of current path
*
*/
getCurrentRouterPath(): Array<string> {
return this.router.url.split('/').filter(path => path);
}
}
我正在尝试通过路由器 mocking 对其进行测试:
import {TestBed, async, inject} from '@angular/core/testing';
import {BreadcrumbService} from './breadcrumb.service';
import {ActivatedRoute, Router} from '@angular/router';
class MockRouter {
navigateByUrl(url: string) {
return { url };
}
}
describe('BreadcrumbService', () => {
let service: BreadcrumbService;
let activateRoute: ActivatedRoute;
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
{ provide: Router, useClass: MockRouter },
{ provide: ActivatedRoute }
]
});
activateRoute = TestBed.inject(ActivatedRoute);
service = TestBed.inject(BreadcrumbService);
}));
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should return an array of route path', inject([Router], (router: MockRouter) => {
const spy = spyOn(router, 'navigateByUrl');
router.navigateByUrl('/giveaway/all');
const arrayPath = service.getCurrentRouterPath();
expect(arrayPath).not.toBeNull();
expect(arrayPath).not.toBeUndefined();
expect(arrayPath).toEqual(['giveaway', 'all']);
}));
});
...但是 url 始终未定义,因此cannot read property 'split of undefined occurs.
我试过的
所以我决定模拟 url 属性本身以避免这种情况:
class MockRouter {
private _url = '';
get url(): string {
return this._url;
}
set url(value: string) {
this._url = value;
}
}
现在测试运行,但 url 属性始终为空,所以我得到一个空数组,因此测试失败。
好的,所以我可以通过直接在模拟上明确设置 url 来完成此操作,但这对我来说似乎是错误的,因为它完全跳过了导航步骤(你注意到我从模拟类中删除了navigateByUrl
):
it('should return an array of route path', inject([Router], (router: MockRouter) => {
router.url = '/giveaway/all';
const arrayPath = service.getCurrentRouterPath();
expect(arrayPath).not.toBeNull();
expect(arrayPath).not.toBeUndefined();
expect(arrayPath).toEqual(['giveaway', 'all']);
}));
所以这里真的有3个问题:
我不应该是 mocking 路由器并实际注入真正的路由器并在测试中实际触发导航事件吗? (试过了,它永远不会失败! - 请参阅下面的注释)
(1)如果我只是 go 与上面的工作是否重要,因为它确实测试了服务中的方法?
我什至是否需要测试这种方法,因为它实际上依赖于其他开发人员已经测试过的其他东西(即 Angular 路由器,阵列拆分和过滤器)。
笔记
我继承了代码,它最初如下所示,测试永远不会失败:
import {TestBed} from '@angular/core/testing';
import {BreadcrumbService} from './breadcrumb.service';
import {RouterTestingModule} from '@angular/router/testing';
import {ActivatedRoute, Router} from '@angular/router';
import {NgZone} from '@angular/core';
describe('BreadcrumbService', () => {
let service: BreadcrumbService;
let router: Router;
let activateRoute: ActivatedRoute;
let ngZone: NgZone;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([])]
});
router = TestBed.inject(Router);
activateRoute = TestBed.inject(ActivatedRoute);
service = TestBed.inject(BreadcrumbService);
ngZone = TestBed.inject(NgZone);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should receive a array of route path', () => {
ngZone.run(() => {
router.navigateByUrl('/giveaway/all').then(() => {
const arrayPath = service.getCurrentRouterPath();
expect(arrayPath).not.toBeNull();
expect(arrayPath).not.toBeUndefined();
expect(arrayPath.length).toEqual(2);
});
});
});
});
无论您调用的导航长度或相等性测试如何,它总是通过。 所以即使这样也通过了:
expect(arrayPath.length).toEqual(200)
和这个:
expect(arrayPath.length).toEqual(0)
这似乎很奇怪。
如果有人能够解释为什么使用实际的路由器和导航不起作用,我将非常感激!
当我需要测试使用路由器的东西时,我会尽可能地模拟。 测试时路由总是很棘手。 当我查看您的服务时,它做了一些非常简单的事情,并且无论导航如何都可以进行测试。 所以我会按如下方式测试它
const testUrl = '/some/test/url';
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
{
provide: Router,
useValue: {
url: testUrl
}
}
]
});
activateRoute = TestBed.inject(ActivatedRoute);
service = TestBed.inject(BreadcrumbService);
}));
it('should return an array of route path', () => {
const arrayPath = service.getCurrentRouterPath();
expect(arrayPath).not.toBeNull();
expect(arrayPath).not.toBeUndefined();
expect(arrayPath).toEqual(['some', 'test', 'url']);
}));
您的测试不应该关心url
的设置方式。 那是别人的工作。 您应该假设Router
经过良好测试,并且url
在导航时已正确设置。 否则,我们的测试将变得过于复杂而无法编写和维护。
要回答您的另一个问题,为什么测试总是通过
在it
运行异步代码可能会导致意外行为。 您的测试始终通过,因为测试在 async function 执行之前完成。 所以, expect....
在测试已经完成(并通过)时执行。 要保持测试直到你运行你的代码,你可以使用done
如下
it('should receive a array of route path', (done) => {
ngZone.run(() => {
router.navigateByUrl('/giveaway/all').then(() => {
const arrayPath = service.getCurrentRouterPath();
expect(arrayPath).not.toBeNull();
expect(arrayPath).not.toBeUndefined();
expect(arrayPath.length).toEqual(2);
done(); // mark the test as done
});
});
});
有关测试异步函数的更多信息,您可以在此处阅读
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.