【问题标题】:Best testing for observable in template模板中可观察的最佳测试
【发布时间】:2017-07-13 18:46:18
【问题描述】:

这是正在测试的组件:

@Component({
  moduleId: module.id,
  selector: 'my-search',
  templateUrl: 'search.component.html',
  styleUrls: ['search.component.css'],
})
export class SearchComponent implements OnInit {

  things: Observable<Thing[]>;

  private searchTerms = new Subject<string>();

  constructor(private searchService: SearchService) { }

  ngOnInit() {
    this.things = this.searchTerms
      .debounceTime(300)
      .distinctUntilChanged()
      .switchMap((term: string) => term
        ? this.searchService.search(term)
        : Observable.of<Thing[]>([]));
  }

  search(term: string) {
    this.searchTerms.next(term);
  }
}

这里是 search.component.html:

<form (submit)="search()">
  <input #searchBox (keyup)="search(searchBox.value)" />
  <button type="submit">Search</button>
</form>

<div *ngIf="(things | async)?.length == 0; else searchResults">No things found.</div> 
<ng-template #searchResults>
  <div class="search-results">
    <div *ngFor="let thing of things | async" class="search-result">
      {{thing.id}}
    </div>
  </div>
</ng-template>

这是失败的测试:

it('should exhibit issue', fakeAsync(() => {
    component.ngOnInit();
    fixture.detectChanges();

    component.search('123');
    tick(300);
    fixture.detectChanges();

    component.things.subscribe((things) => {
        // This fails. (I've tried various things, this is just the latest attempt.)
        expect(dom.querySelectorAll('.search-results .search-result').length).toBe(1);
    });
}));

Here's a plunk with what I've got so far.

无论我做什么,我都看不到 DOM 的变化。 fixture.detectChanges() 对 DOM 没有任何作用。

如何测试 Observables?

【问题讨论】:

  • 在单元测试中不需要做component.things.subscribe()。调用component.search('123'); 后,您已经测试了组件中发生的变化。如果必须在模板中更改某些内容,则使用类或 ID 在模板中选择相应的元素并对其进行测试。如果属性的值必须改变,那么测试一下。

标签: angular unit-testing asynchronous angular-components


【解决方案1】:

这对我有用

const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
fixture.detectChanges();
app.search('123');
tick(400);
fixture.detectChanges();
const searchNodes = fixture.debugElement.queryAll(By.css('.search-results .search-result')).map((item) => item.nativeElement);
expect(searchNodes.length).toBe(3);

【讨论】:

  • tick 仅适用于fakeAsyncfakeAsync 不会检索外部模板。
【解决方案2】:

终于搞定了。您可以查看the plunk (version 25),但这里是精简的解决方案:

it('now works!', async(() => {
    // Initialize the component.
    component.ngOnInit();
    fixture.detectChanges();

    // The Observable is now initialized and we can now subscribe.
    component.things.subscribe((things) => {
        // Now that we've got the data, look for changes.
        fixture.detectChanges();

        // The DOM/view should now be up to date.
        expect(dom.querySelectorAll('.search-results .search-result').length).toBe(1);
    });

    // Initiate stuff happening.
    component.search('123');
}));

亮点:

  • 使用async 而不是fakeAsync
  • 记得在您的订​​阅中致电detectChanges,以便更新视图。

我要注意的一件事:在这种情况下,subscribe 是在事件之前还是之后出现(在示例中调用 search)似乎并不重要。我把它放在前面作为预防措施,因为“热”的 Observable 可能会在 subscribe 注册之前处理事件;然后观察者将错过通知,回调将永远不会触发,并且测试将无效。

【讨论】:

  • 不幸的是,如果 Observable 由 MockNgRedux / Redux 商店提供,这将不起作用;(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
  • 2017-12-02
  • 1970-01-01
  • 2018-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多