首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >单元测试NgRx效果,以确保服务方法被称为“不工作”

单元测试NgRx效果,以确保服务方法被称为“不工作”
EN

Stack Overflow用户
提问于 2019-01-21 15:19:02
回答 1查看 4.9K关注 0票数 6

我使用的是NgRx ^7.0.0版本。这是我的NgRx效果课程:

代码语言:javascript
运行
复制
import { Injectable } from '@angular/core';
import { ApisService } from '../apis.service';
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Observable } from 'rxjs';
import { ApisActionTypes, ApisFetched } from './apis.actions';
import { mergeMap, map } from 'rxjs/operators';

@Injectable()
export class ApisEffects {

  constructor(private apisS: ApisService, private actions$: Actions) { }

  @Effect()
  $fetchApisPaths: Observable<any> = this.actions$.pipe(
    ofType(ApisActionTypes.FetchApisPaths),
    mergeMap(() =>
      this.apisS.fetchHardCodedAPIPaths().pipe(
        map(res => new ApisFetched(res))
      )
    )
  );
}

这是个简单的测试。正如你所看到的,它应该会失败,但总是会过去。我在StackOverflow How to unit test this effect (with {dispatch: false})?上遵循了类似的问题,但是它对我不起作用,就好像代码执行从来没有进入effects.$fetchApisPaths.subscribe块一样

代码语言:javascript
运行
复制
import { TestBed } from '@angular/core/testing';
import { provideMockActions } from '@ngrx/effects/testing';
import { hot, cold } from 'jasmine-marbles';
import { Observable, ReplaySubject } from 'rxjs';
import { ApisEffects } from '../state/apis.effects';
import { ApisFetch, ApisFetched } from '../state/apis.actions';
import { IApiPath } from '../models';
import { convertPaths, getAPIPathsAsJson, ApisService } from '../apis.service';
import { ApisServiceMock } from './mocks';

describe('Apis Effects', () => {
  let effects: ApisEffects;
  let actions: Observable<any>;
  let apisS: ApisService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        ApisEffects,
        provideMockActions(() => actions),
        {
          provide: ApisService,
          useClass: ApisServiceMock
        }
      ]
    });

    effects = TestBed.get(ApisEffects);
    apisS = TestBed.get(ApisService);
  });

  it('should call ApisService method() to get Api Paths', () => {
    const spy = spyOn(apisS, 'fetchHardCodedAPIPaths');

    const action = new ApisFetch();
    actions = hot('--a-', {a: action});

    effects.$fetchApisPaths.subscribe(() => {
      console.log('%c effect trigerred', 'color: orange; border: 1px solid red;');
      // expect(spy).toHaveBeenCalled();
      expect(true).toBe(false); // never fails
    });
  });
});

以防万一我对动作做了一些愚蠢的事情,下面是动作文件:很可能我没有,因为它在应用程序中正常工作。

代码语言:javascript
运行
复制
import { Action } from '@ngrx/store';
import { IApiPath } from '../models';

export enum ApisActionTypes {
    FetchApisPaths = '[Apis] Fetch Paths',
    FetchedApisPaths = '[Apis] Fetched Paths'
}

export class ApisFetch implements Action {
    readonly type = ApisActionTypes.FetchApisPaths;
}

export class ApisFetched implements Action {
    readonly type = ApisActionTypes.FetchedApisPaths;
    constructor(public payload: IApiPath[]) {}
}

export type ApisActions = ApisFetch | ApisFetched;

=======================EDIT==============================

我使用了官方ngrx https://ngrx.io/guide/effects/testing中的一个示例,现在我可以成功地输入下面的订阅块,我记录了两个控制台日志,但是测试成功了。这太奇怪了!我尝试过从订阅块抛出错误,但是测试仍然成功。

代码语言:javascript
运行
复制
it('should work also', () => {
    actions$ = new ReplaySubject(1);

    actions$.next(new ApisFetch());

    effects.$fetchApisPaths.subscribe(result => {
      console.log('will be logged');
      expect(true).toBe(false); // should fail but nothing happens - test succeeds
      console.log(' --------- after '); // doesn't get called, so the code
      // execution stops on expect above
    });
  });
EN

Stack Overflow用户

回答已采纳

发布于 2019-01-22 13:01:12

好吧,我让它起作用了。为了成功地测试是否从NgRx效果中调用了特定的角服务方法,我将一个测试用例封装在一个async中。

代码语言:javascript
运行
复制
  it('should call ApisService method to fetch Api paths', async () => {
    const spy = spyOn(apisS, 'fetchHardCodedAPIPaths');

    actions$ = new ReplaySubject(1);
    actions$.next(new ApisFetch());
    await effects.$fetchApisPaths.subscribe();
    
    expect(spy).toHaveBeenCalled();
  });

await effects.$fetchApisPaths.subscribe();来阻止执行,并在下一行中运行测试断言。

现在,当我尝试运行expect(true).toBe(false);来测试测试是否失败时,它正确地失败了。

问题中我的代码(如ngrx https://ngrx.io/guide/effects/testing中的https://ngrx.io/guide/effects/testing示例)的问题是,当断言位于.subscribe()块中时,不可能失败测试。那里发生了一些不确定的事情,我仍然不知道为什么代码会以下列方式运行:

代码语言:javascript
运行
复制
effects.$fetchApisPaths.subscribe(result => {
  console.log('will be logged');  // 1) gets logged
  expect(true).toBe(false);       // 2) should fail
  console.log(' - after ');       // 3) doesn't get called
});  

因此,代码执行在2)上停止,测试用例返回正,而行3)永远不会执行。

因此,ngrx中带有.subscribe()块内断言的测试用例将始终是绿色的,为您的测试用例提供了一个假阳性。这就是我在ngrx ^7.0.0中所经历的行为

编辑2020年9月-更新ngrx版本9。如果上面的解决方案不适用于您,也不适用于将来的我,因为我再次面临同样的问题,只找到我自己的答案来帮助和伟大的评论@Christian来引导我找到ngrx gitter的问题,试试这个方法:

代码语言:javascript
运行
复制
 it('should call ApisService method to fetch Api paths', async () => {
  const spy = spyOn(apisS, 'fetchHardCodedAPIPaths');

  actions$ = cold('--a-', {
      a: ControlCenterTrendsLineChartPeriodChange({ numberOfMonths: 24 })
  });
  await effects.$fetchApisPaths.subscribe();

  expect(actions$).toSatisfyOnFlush(() => {
      expect(spy).toHaveBeenCalled();
});
票数 9
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54292921

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档