对 NgRx 效果进行单元测试以确保服务方法被调用 - 不起作用

2023-12-22

我正在使用 NgRx ^7.0.0 版本。 这是我的 NgRx 效果类:

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 上关注了类似的问题如何对这种效果进行单元测试(使用 {dispatch: false})? https://stackoverflow.com/questions/48318095/how-to-unit-test-this-effect-with-dispatch-false但它对我不起作用,就好像代码执行永远不会进入effects.$fetchApisPaths.subscribe块

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
    });
  });
});

以防万一我在操作上做了一些愚蠢的事情,这里是操作文件: 我很可能不是,因为它按预期在应用程序中工作。

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;

=======================编辑============================ ====

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

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
    });
  });

好的,所以我成功了。为了成功测试是否从 NgRx 效果中调用特定的 Angular 服务方法,我将一个测试用例包装在async:

  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();
  });

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

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

问题中我的代码存在问题(示例为ReplaySubject如 ngrx 文档中所示https://ngrx.io/guide/effects/testing https://ngrx.io/guide/effects/testing)是当断言在内部时不可能使测试失败.subscribe()堵塞。那里发生了一些可疑的事情,我仍然不知道为什么代码会以以下方式运行:

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 问题,请尝试这个方法:

 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();
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对 NgRx 效果进行单元测试以确保服务方法被调用 - 不起作用 的相关文章

随机推荐

  • iPhone 的网络时间协议

    我正在编写一个需要精确计时的应用程序 问完后这个问题 https stackoverflow com questions 2264197 how to accurately sync time between iphones 我决定使用 N
  • 如何在打字稿Angular 4中将字符串转换为布尔值

    我知道我不是第一个问这个问题的人 正如我在标题中提到的 我正在尝试将字符串值转换为布尔值 我之前已将一些值放入本地存储中 现在我想获取所有值并将所有值分配给一些布尔变量 应用程序组件 ts localStorage setItem Chec
  • 我可以使用 GenericServlet 在 Tomcat 上实现套接字服务器吗?

    我想实现一个将由多个客户端连接的套接字服务器 为了使实现尽可能简单 并且不必对线程和连接等进行代码管理 我想使用 Tomcat 我们已经使用 tomcat 作为我们解决方案的一部分 我确信 Tomcat 可以用于非 http servlet
  • 优化php中的大导入

    我有一个简单的导入器 它会遍历相当大的 csv 的每一行并将其导入到数据库中 我的问题是 我应该调用另一个方法来插入每个对象 生成 DO 并告诉它的映射器插入 还是应该在导入方法中对插入过程进行硬编码 复制代码 我知道最优雅的做法是调用第二
  • idea intellij maven项目无法make

    我有 Maven 项目 Maven 构建完成成功 但我无法完成这个项目 信息 取得成功 项目包含一个模块 Idea 看不到依赖关系 Error 3 38 java D Dropbox Programming java spring spri
  • Javascript垂直居中div(可变高度)

    我正在尝试使用 Javascript 将 div 垂直居中 因为文本会发生变化 所以我不能使用固定的高度 我想做这个without Jquery box2 width 100 height 100 position relative bac
  • UITableViewCells 初始加载视图/显示问题

    所以我有一个UITableView加载多列报价 进入后UITableView显示此数据时 单元格最初似乎未正确加载 文本看起来确实被压扁和 或被切断 大约 1 2 秒后 它正确加载 一切正常 每次加载表视图时都会发生这种情况 例如 这是一个
  • 使用 DateTime 列设置 LinqDataSourceWhere 子句

    在 C net 中 我有以下数据源设置 我试图在后面的代码中动态分配 WHERE 子句
  • MySQL:在已填充的表中创建新的唯一字段

    我需要在数据库表中创建一个已填充数据的字段 当然 仅仅将字段添加为空是不可能的 我只能想到创建一个新结构的新表 并将现有数据复制到新表中 但我想知道是否有更简单的方法 提示 它是一个复合键 由同一个表中的其他 3 个字段组成 编辑 该字段保
  • 提取 msi 时出现错误 2203

    我在使用以下命令提取 msi 时收到 2203 错误 msiexec a C Test Installer msi QB targetDIR C Test Eval LV C Test INST Logfile log 回答时请考虑以下几点
  • 使用相对路径时 VS10 附加库目录失败

    当我使用相对路径设置项目时 它失败了 不起作用 属性 链接器 常规 附加库目录 libraries 工作正常 C Users NAME Desktop project libraries 如何使相对路径发挥作用 尝试使其相对于您的项目目录或
  • 如何获取匹配 REGEX 后的文本

    我有字符串 我的家 和正则表达式 例如 reg hom 我正在努力找出如何在比赛后获取文本 直到单词结尾 在本例中我正在寻找 e 另一个例子 string soulful reg soul gt gt gt 我需要 完整 先感谢您 您可以使
  • GCC 内存屏障 __sync_synchronize 与 asm 易失性("": : :"内存")

    asm volatile memory 通常用作内存屏障 例如 如 Linux 内核中所示 barrier macro 这听起来类似于 GCC 内置的 sync synchronize http gcc gnu org onlinedocs
  • 气流错误:AttributeError:模块“airflow.utils.log”没有属性“file_processor_handler”

    我的本地气流即时已启动并正在运行 但现在当我运行气流网络服务器或任何其他气流命令时 我收到以下错误 带有一些回溯 Unable to load the config contains a configuration error Traceb
  • 通过代码向 Winforms DataGridView 添加新列

    我正在尝试为给定月份的每一天添加 N 列 var daysCount DateTime DaysInMonth DateTime Now Year month for int i 1 i lt daysCount i dataGridVie
  • 有条件地平均 DataTable 中的一列数据

    我有一个 DataTable 对象 dTable 其中所有 DataColumn 数据类型都是字符串或双精度 列中的某些数字不存在 即 空 现在我有下面的代码来查找平均值 并且当有值时它效果很好 var sum dTable AsEnume
  • 如何在没有流或系统 io 的情况下压缩字节数组

    我正在尝试将图像编码为字节数组并将其发送到服务器 编码和发送部分工作正常 但我的问题是字节数 组太大并且发送时间太长 所以我认为压缩它会让它运行得更快 但实际的问题是我不能使用 system io 或流 我的目标是 net 2 0 谢谢 u
  • 如何判断一个图是否有环?

    我知道这个问题在这个论坛和互联网上的其他地方已经被问过很多次了 但在你伸出爪子攻击我之前 请耐心等待 我是一个新手学习图 作为练习的一部分 我在此处的 Graph 类中添加了一个方法 has Cycle http homepage cs u
  • 当存在重复索引时,numpy 会保留分配顺序吗?

    我想通过索引数组对数组进行赋值 但存在重复的索引 例如 a np arange 5 index np array 1 2 3 1 2 3 1 2 3 b np arange 9 a index b 两个问题 对于重复索引 最新的分配总是生效
  • 对 NgRx 效果进行单元测试以确保服务方法被调用 - 不起作用

    我正在使用 NgRx 7 0 0 版本 这是我的 NgRx 效果类 import Injectable from angular core import ApisService from apis service import Effect