Angular 如何测试需要位置的组件
Posted
技术标签:
【中文标题】Angular 如何测试需要位置的组件【英文标题】:Angular How to test a Component which requires a Location 【发布时间】:2018-06-20 11:40:22 【问题描述】:您好,感谢您抽出宝贵时间!
我正在学习如何使用 Angular,并且我有兴趣学习如何测试其组件。
目前我正在苦苦挣扎,因为我已经完成了 Angular 页面的英雄之旅教程,并且我正在测试代码以更好地理解它。
关键是我正在测试 hero-details 组件的代码是:
import Component, OnInit, Input from '@angular/core';
import ActivatedRoute from '@angular/router';
import MyHeroService from '../hero-service/my-hero.service';
import Location from '@angular/common';
import Hero from '../Hero';
@Component(
selector: 'app-hero-details',
templateUrl: './hero-details.component.html',
styleUrls: ['./hero-details.component.css']
)
export class HeroDetailsComponent implements OnInit
@Input() hero: Hero;
constructor(private route: ActivatedRoute,
private myHeroService: MyHeroService,
private location: Location)
ngOnInit(): void
this.getHero();
getHero(): void
const id = +this.route.snapshot.paramMap.get('id');
this.myHeroService.getHero(id)
.subscribe(hero => this.hero = hero);
goBack(): void
this.location.back();
我的测试试图证明 getHero() 在创建 hero-details 组件后被调用:
import HeroDetailsComponent from './hero-details.component';
import ActivatedRoute from '@angular/router';
import MyHeroService from '../hero-service/my-hero.service';
import MessageService from '../message.service';
import Location from '@angular/common';
import provideLocationStrategy from '@angular/router/src/router_module';
import BrowserPlatformLocation from '@angular/platform-browser/src/browser/location/browser_platform_location';
describe('heroDetails', () =>
it('should call getHero after being created', () =>
const heroDetailsComponent = new HeroDetailsComponent(new ActivatedRoute(),
new MyHeroService(new MessageService([])),
new Location(provideLocationStrategy(new BrowserPlatformLocation(['anyParameter']), '/')));
spyOn(heroDetailsComponent, 'getHero');
heroDetailsComponent.ngOnInit();
expect(heroDetailsComponent.getHero()).toHaveBeenCalled();
);
);
我面临的困难是当我尝试创建一个新的 Location 时,它是 Hero-datail 组件的构造函数的必需参数。
第一个Location的参数是一个PlatformStrategy,所以我用provider来构建它。此外,提供者需要一个看起来很抽象的 PlatformLocation(),所以我选择了我能找到的唯一实现,即 BrowserPlatformLocation。
在所有这些过程之后,测试执行说:
而且浏览器永远不会结束加载套件:
这里奇怪的是,IDE 确实找到了这些模块,因为我可以导航到它们。
此外,如果我注释掉该测试,该套件运行良好:
另外我也读过:
-
https://angular.io/api/common/Location
https://www.tektutorialshub.com/location-strategies-angular/
https://angular.io/tutorial/toh-pt5
我怎样才能以正确的方式对其进行测试?我在哪里可以找到有关正确进行此类测试的更多信息?这个测试如何轻松模拟 Location 参数?
感谢您阅读本文
【问题讨论】:
【参考方案1】:Location
是内置服务,不需要实例化,mock一下即可:
const locationStub =
back: jasmine.createSpy('back')
然后在您的providers
数组中:
providers: [ ..., provide: Location, useValue: locationStub ],
然后在您的测试中调用组件goBack
方法,然后使用Injector
获取您的服务存根的实例,如下所示:
const location = fixture.debugElement.injector.get(Location);
然后只是测试,back
函数已被调用:
expect(location.back).toHaveBeenCalled();
这应该可以解决问题。据我所知,这是处理内置服务的最佳方式,您不需要测试它们(Angular 团队已经这样做了),只需模拟它们并确保它们被正确调用
【讨论】:
我使用 expect((location as any).back).toHaveBeenCalledTimes(1);避免编译错误 “位置”类型上不存在属性“后退”。 @MiomirDancevic 那么你的“位置”有误,请确保你使用来自@angular/common
的课程【参考方案2】:
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [ HeroDetailsComponent ],
providers: [ MyHeroService ],
imports: [ RouterTestingModule ],
providers: [ provide: Location, useClass: SpyLocation ]
)
.compileComponents();
));
it('should logout from application', async(() =>
const location: Location = TestBed.get(Location);
expect(location.href).toContain('blablabla url');
));
使用来自 @angular/router/testing 的 SpyLocation
【讨论】:
那是什么角度的版本?SpyLocation
不存在。
也许您在查看 @angular/core,但它在 Angular 11 中是 @angular/common。 import SpyLocation from '@angular/common/testing';
这是一个很好的答案,但据我了解这里的文档 (angular.io/api/router/testing/RouterTestingModule) 您不必在 providers
array 中明确定义您的 Location
提供程序,因为 RouterTestingModule
已经提供它。在您的情况下,您使用相同的代码覆盖它。我也测试过了。【参考方案3】:
如果我是你,我不会费心从头开始创建测试:CLI 会创建预制测试。
在这些测试中,有一个 TestBed,用于设置一个测试模块来测试您的组件。如果你使用它,你只需要导入一个路由器测试模块。
这会给出这样的结果:
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [ HeroDetailsComponent ],
providers: [ MyHeroService ],
imports: [ RouterTestingModule ]
)
.compileComponents();
));
就这样,你的整个路由策略就被嘲笑了。
【讨论】:
以上是关于Angular 如何测试需要位置的组件的主要内容,如果未能解决你的问题,请参考以下文章