【问题标题】:How to unit test search functionality?如何对搜索功能进行单元测试?
【发布时间】:2020-11-01 02:17:57
【问题描述】:

首先,我只是单元测试或一般测试的新手,所以我仍在思考一些概念。已经掌握了单元测试的基础知识,并且我目前也在学习 rxjs 大理石测试,所以目前我一直坚持如何使用文档中的代码以相同的方式测试搜索 w/c 函数。

所以让我们在 Angular 文档中使用英雄之旅中的代码

this.heroes$ = this.searchTerms.pipe(
  // wait 300ms after each keystroke before considering the term
  debounceTime(300),

  // ignore new term if same as previous term
  distinctUntilChanged(),

  // switch to new search observable each time the term changes
  switchMap((term: string) => this.heroService.searchHeroes(term)),
);

这是我目前的测试结果

const searchResults$ = (inputs$: Observable<string>) =>
  inputs$.pipe(
    debounceTime(300),
    distinctUntilChanged(),
    switchMap((term: string) => fakeHeroService.searchHeroes(term))
  );

  it('should return the correct results', () => {
    scheduler.run(helpers => {
      const { cold, hot, expectObservable } = helpers;

      // these are the search terms typed by user, observable
      // emitted by this.searchTerms
      const inputMarbles = '^-a 300ms b-c 300ms';

      // each emitted response by each service call
      const outputMarbles = '-- 300ms a-- 300ms c';

      // verify that service is called N times
      // verify that it's passed with certain argument per run


      searchServiceSpy = spyOn(heroService, 'searchHeroes').and.returnValue(
        cold(outputMarbles)
      );
      const source$ = hot(inputMarbles);

      const output$ = source$.pipe(searchResults$);

      expectObservable(output$).toBe(outputMarbles);

      /* expect(fakeSearchService.getMatches).toHaveBeenCalledTimes(2); */
    });
  });

我只是无法让它工作。

【问题讨论】:

  • 我更喜欢 cypress 进行所有测试。可能想检查一下。
  • @John Peter's 不只是用于 e2e 测试吗?在这种情况下我应该跳过单元测试吗?
  • 是的,这是我的建议,因为 Cypress 可以覆盖所有端点测试以及拦截 HTTPClient 请求(入站或出站)您可以隔离覆盖所有边界的 API 以及执行相同边界测试的前端。其他任何事情都必须从内部进行模拟,例如关闭数据库或清除依赖于应用程序运行的数据库条目。赛普拉斯模糊了传统测试定义的界限。
  • 我已经被这个问题困扰了好几天了,所以如果我找不到解决方案,我可能会采用柏树的方式
  • 赛普拉斯很棒。我什至是柏树大使,我为此进行了大量培训。但恕我直言,它不能替代单元测试。使用 cypress 测试诸如确保您有 300 毫秒的谴责之类的东西实际上并不可行。随着时间的推移,您没有那种细粒度的控制。但是很多人为了集成/e2e 而避开单元测试。但对我来说这是一个错误。单元测试(尤其是使用 TDD 完成时)并没有真正被 cypress 之类的东西所取代。

标签: angular unit-testing jasmine tdd


【解决方案1】:

我建议在单独的测试中测试链的每个部分(debounce、disticnt、switchMap)。

您可以将observer-spyfakeAsync 组合使用,以便更轻松地进行测试。

例如,要测试debounce,你可以这样写(以下代码可能不完整,但这只是为了说明这一点)-

import {subscribeAndSpyOn} from '@hirez_io/observer-spy';

it('should debounce by 300 ms', fakeAsync(() => {

  // basically with "debounce" you only care if 2 triggers happened and enough time passed, 
  // the number of results should be 1...

  const observerSpy = subscribeAndSpyOn(serviceUnderTest.heroes$);
  serviceUnderTest.searchTerms.next();
  tick(100);
  serviceUnderTest.searchTerms.next();
  tick(300);
  expect(observerSpy.getValuesLength).toBe(1);

}));


并为其他使用“恰到好处原则”的其他运营商编写类似的测试来为链中的其他运营商设置条件。

【讨论】:

  • Shai 的建议是每个人都应该接受的。 :)
  • 谢谢,我想试图用很多概念来围绕我的脑袋让我感到困惑,我被困住了,唯一的测试方法是使用 rxjs-marble 测试。在这种情况下,我觉得这个更容易。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 2022-11-29
  • 2018-02-25
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多