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

时间:2018-01-11 07:43:26

标签: javascript angular unit-testing jasmine

您好,谢谢您的时间!

我正在学习如何使用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():

 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,因此我使用提供程序来构建它。此外,提供者需要一个看起来像抽象的PlatformLocation(),然后我选择了我能找到的唯一一个是BrowserPlatformLocation的实现。

在所有这个过程之后,测试执行说: enter image description here

浏览器永远不会结束加载套件: enter image description here

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

此外,如果我评论该测试,套件效果很好:

enter image description here

另外我还读过:

我怎么能以正确的方式测试它?我在哪里可以找到有关正确进行此类测试的更多信息?怎么能做这个测试来轻松模拟Location参数?

感谢您阅读

3 个答案:

答案 0 :(得分:1)

如果我是你,我不打算从头开始创建测试:CLI创建预先制作的测试。

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

这可能是这样的:

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

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

答案 1 :(得分:1)

Location是一个内置服务,你不需要实例化它,只需模仿它:

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团队已经这样做了),只是模拟它们并确保它们被正确调用< / p>

答案 2 :(得分:0)

     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