如何对依赖ActivatedRoute参数的组件进行单元测试?

Col*_*Cox 70 unit-testing angular2-routing angular2-testing angular

我是一个单元测试用于编辑对象的组件.该对象具有唯一性id,用于从服务中托管的对象数组中获取特定对象.具体id是通过路由传递的参数获得的,特别是通过ActivatedRoute类传递.

构造函数如下:

 constructor(private _router:Router, private _curRoute:ActivatedRoute, private _session:Session) {
}

ngOnInit() {
    this._curRoute.params.subscribe(params => {
        this.userId = params['id'];
        this.userObj = this._session.allUsers.filter(user => user.id.toString() === this.userId.toString())[0];
Run Code Online (Sandbox Code Playgroud)

我想对这个组件运行基本的单元测试.但是,我不确定如何注入id参数,组件需要此参数.

顺便说一下:我已经有了Session服务的模拟,所以不用担心.

zma*_*anc 107

最简单的方法是使用该useValue属性并提供要模拟的值的Observable.

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
...
{
  provide: ActivatedRoute,
  useValue: {
    params: Observable.of({id: 123})
  }
}
Run Code Online (Sandbox Code Playgroud)

  • Observable.of对我来说不存在!:S (11认同)
  • 此代码在我的项目中出现此错误:`Uncaught NetworkError:无法在'XMLHttpRequest'上执行'send':无法加载'ng:///DynamicTestModule/HomeContentComponent.ngfactory.js'.在http:// localhost:9876/_karma_webpack_/polyfills.bundle.js:2605` (6认同)
  • RxJs 6`of`应该单独使用.你也可能使用`RouterTestingModule`而不是这个答案的代码. (5认同)
  • 从rxjs/Observable导入Observable (4认同)
  • @BenRacicot这个答案是在RxJs 6存在之前给出的。也可以说“执行此操作”来提供可以直接投票的答案。 (3认同)

dim*_*maf 22

在 angular 8+ 中有RouterTestingModule,您可以使用它来访问组件的ActivatedRouteRouter。您也可以将路由传递给RouterTestingModule并为请求的路由方法创建间谍。

例如在我的组件中,我有:

ngOnInit() {
    if (this.route.snapshot.paramMap.get('id')) this.editMode()
    this.titleService.setTitle(`${this.pageTitle} | ${TAB_SUFFIX}`)
}
Run Code Online (Sandbox Code Playgroud)

在我的测试中,我有:

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ ProductLinePageComponent ],
      schemas: [NO_ERRORS_SCHEMA],
      imports: [
        RouterTestingModule.withRoutes([])
      ],
    })
    .compileComponents()
  }))

  beforeEach(() => {
    router = TestBed.get(Router)
    route = TestBed.get(ActivatedRoute)
  })
Run Code Online (Sandbox Code Playgroud)

后来在“它”部分:

  it('should update', () => {
    const spyRoute = spyOn(route.snapshot.paramMap, 'get')
    spyRoute.and.returnValue('21')
    fixture = TestBed.createComponent(ProductLinePageComponent)
    component = fixture.componentInstance
    fixture.detectChanges()
    expect(component).toBeTruthy()
    expect(component.pageTitle).toBe('Edit Product Line')
    expect(component.formTitle).toBe('Edit Product Line')
    // here you can test the functionality which is triggered by the snapshot
  })
Run Code Online (Sandbox Code Playgroud)

类似的,我认为你可以paramMap通过spyOnPropertyjasmine的方法直接测试,通过返回一个observable或者使用rxjs弹珠。它可能会节省一些时间,而且不需要维护额外的模拟类。希望它是有用的,它是有道理的。


Col*_*Cox 16

我已经想出怎么做了!

既然ActivatedRoute是服务,就可以建立一个模拟服务.我们称之为模拟服务MockActivatedRoute.我们将扩大ActivatedRouteMockActivatedRoute,具体如下:

class MockActivatedRoute extends ActivatedRoute {
    constructor() {
        super(null, null, null, null, null);
        this.params = Observable.of({id: "5"});
    }
Run Code Online (Sandbox Code Playgroud)

该行super(null, ....)初始化超类,它有四个必需参数.但是,在这种情况下,我们不需要任何这些参数,因此我们将它们初始化为null值.我们需要的是价值params这是一个Observable<>.因此,使用this.params,我们覆盖它的值params并将其初始化Observable<>为测试主体所依赖的参数.

然后,与任何其他模拟服务一样,只需初始化它并覆盖组件的提供程序.

祝好运!


Rad*_*ady 8

这是我在角度2.0最新测试中的方式...

import { ActivatedRoute, Data } from '@angular/router';
Run Code Online (Sandbox Code Playgroud)

在提供者部分

{
  provide: ActivatedRoute,
  useValue: {
    data: {
      subscribe: (fn: (value: Data) => void) => fn({
        yourData: 'yolo'
      })
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Fra*_*rzi 5

只需添加 ActivatedRoute 的模拟:

providers: [
  { provide: ActivatedRoute, useClass: MockActivatedRoute }
]
Run Code Online (Sandbox Code Playgroud)

...

class MockActivatedRoute {
  // here you can add your mock objects, like snapshot or parent or whatever
  // example:
  parent = {
    snapshot: {data: {title: 'myTitle ' } },
    routeConfig: { children: { filter: () => {} } }
  };
}
Run Code Online (Sandbox Code Playgroud)