Angular 2 / Jasmine,在每个describe / it块中更新激活的route params订阅

时间:2017-03-14 02:24:43

标签: unit-testing angular angular2-testing

给定一个简单的组件,订阅ngOnInit中激活的路由查询参数:

export class FooComponent implements OnInit {
  private queryParams: any;

  constructor(
    private activatedRoute: ActivatedRoute
  ) { }

  ngOnInit() {
    this.activatedRoute.queryParams.subscribe(params => this.queryParams = params);
  }

  active(foo: number): boolean {
    return this.queryParams['foo'] &&
      foo === +this.queryParams['foo'];
  }
}

foo查询参数存在且其值与提供的参数匹配时,活动函数应返回true。

在此组件的附带单元测试中,我想更改每个it块中查询参数的值,以测试查询参数不存在,匹配参数而不匹配参数。

describe('FooComponent', () => {
  let component: FooComponent;
  let fixture: ComponentFixture<FooComponent>;
  let activatedRoute: ActivatedRoute;

  class MockActivatedRoute {
    queryParams = Observable.of({});
  }

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [FooComponent],
      providers: [
        { provide: ActivatedRoute, useClass: MockActivatedRoute }
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(FooComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    activatedRoute = fixture.debugElement.injector.get(ActivatedRoute);
  });

  describe('active', () => {
    it('should return false if the foo query param is not present', () => {
      activatedRoute.queryParams = Observable.of({});
      let result = component.active(100);
      expect(result).toBe(false);
    });

    it('should return false if the foo query param does not match the supplied parameter', () => {
      activatedRoute.queryParams = Observable.of({ foo: '500' });
      let result = component.active(100);
      expect(result).toBe(false);
    });

    it('should return true if the foo query param does not match the supplied parameter', () => {
      activatedRoute.queryParams = Observable.of({ foo: '500' });
      let result = component.active(500);
      expect(result).toBe(true);
    });
  });
});

而是FooComponent类的私有queryParams成员的值不会在每个it块中更新。我尝试了asyncfixture.whenStable()fakeAsync/tick的各种方法。

如何更新每个单元测试的订阅价值?

1 个答案:

答案 0 :(得分:3)

这是因为您正在分配一个新的Observable,但客户端已经订阅了第一个Observable。这是因为首次调用ngOnInit时会调用fixture.detectChanges()。如果您在之后等待调用fixture.detectChanges() ,则将新的Observable分配给queryParams,然后将使用该Observable。

另一个选项(可能是首选)是代替使用Observable,您可以使用Subject。有了这个,您可以控制何时发出数据以及发射什么。

import { Subject } from 'rxjs/Subject'
import { fakeAsync, tick } from

class MockActivatedRoute {
  queryParams = new Subject<any>();
}

let route: MockActivatedRoute;

beforeEach(() => {
  /* configure */ 

  route = <MockActivatedRoute>TestBed.get(ActivatedRoute);
})

it('', fakeAsync(() => {
  route.queryParams.next(newparams);    // emit something
  tick();                               // wait for resolution
  fixture.detectChanges();              // detect changes (for ui)
  expect(...)
}))

我说这个选项可能是首选,因为它允许在同一个测试中发出多个值。