Angular如何测试需要位置的组件

Eno*_*noy 5 javascript unit-testing jasmine angular

您好,感谢您的宝贵时间!

我正在学习如何使用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();
  }
}
Run Code Online (Sandbox Code Playgroud)

我的测试试图证明在创建hero-details组件后调用了getHero():

 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();



      });
    });
Run Code Online (Sandbox Code Playgroud)

我面临的困难是当我尝试创建一个新位置时,这是Hero-datail组件的构造函数的必需参数。

第一个Location的参数是PlatformStrategy,因此我使用了提供程序来构建它。另外,提供程序还需要一个PlatformLocation(),它看起来像是抽象的,所以我选择了唯一可以找到的实现,即BrowserPlatformLocation。

完成所有这些过程后,测试执行将显示: 在此处输入图片说明

浏览器永远不会停止加载套件: 在此处输入图片说明

奇怪的是,IDE确实找到了那些模块,因为我可以导航到它们。

另外,如果我注释掉该测试,该套件也可以正常工作:

在此处输入图片说明

另外,我也读过:

我该如何以正确的方式进行测试?在哪里可以找到有关正确进行此类测试的更多信息?该测试如何轻松模拟该Location参数?

谢谢您阅读此篇

Mac*_*nto 6

     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');
   }));
Run Code Online (Sandbox Code Playgroud)

使用来自@angular/router/testing 的 SpyLocation

  • 那是什么角度版本?“SpyLocation”不存在。 (2认同)

Arm*_*yan 5

Location 是内置服务,您无需实例化它,只需对其进行模拟即可:

const locationStub = {
    back: jasmine.createSpy('back')
}
Run Code Online (Sandbox Code Playgroud)

然后在您的providers数组中:

providers: [ ..., {provide: Location, useValue: locationStub} ],
Run Code Online (Sandbox Code Playgroud)

然后在您的测试中,只需调用components goBack方法,然后使用Injector即可获取服务存根的实例,如下所示:

const location = fixture.debugElement.injector.get(Location);
Run Code Online (Sandbox Code Playgroud)

然后测试一下,该back函数已被调用:

expect(location.back).toHaveBeenCalled();
Run Code Online (Sandbox Code Playgroud)

这应该可以解决问题。据我所知,这是处理内置服务的最佳方法,您无需测试它们(Angular团队已经做到了),只需对其进行模拟并确保已正确调用它们即可。

  • “位置”类型上不存在属性“后退”。 (2认同)
  • @MiomirDancevic 那么你的“位置”是错误的,请确保你使用“@angular/common”中的类 (2认同)

小智 3

如果我是您,我不会费心从头开始创建测试:CLI 创建预制测试。

在这些测试中,有一个 TestBed,用于设置测试模块来测试您的组件。如果你使用它,你只需要导入一个路由器测试模块。

这会给出这样的结果:

beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [ HeroDetailsComponent ],
    providers: [ MyHeroService ],
    imports: [ RouterTestingModule ]
  })
    .compileComponents();
}));
Run Code Online (Sandbox Code Playgroud)

就这样,你的整个路由策略就被嘲笑了。