单元测试NgRx效果以确保调用了服务方法-不起作用 [英] Unit testing NgRx effect to ensure the service method was called - ain't working

查看:115
本文介绍了单元测试NgRx效果以确保调用了服务方法-不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using NgRx ^7.0.0 version. This is my NgRx effect class:

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})?,但对我来说不起作用,就好像代码执行从未进入效果.

And that's a simple test. As you can see it should fail, but is always passing. I followed similar question here on StackOverflow How to unit test this effect (with {dispatch: false})? but it doesn't work for me, as if the code execution never enters the effects.$fetchApisPaths.subscribe block

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

以防万一我对动作做傻了,这是动作文件: 我很可能不是,因为它可以按预期在应用程序中工作.

Just in case I am doing smthg stupid with actions, here is the actions file: Most likely I am not, since it's working in the app as expected.

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/测试,现在我可以成功输入下面的subscribe块,同时记录了两个控制台日志,但是测试成功.这很奇怪!我尝试从订阅块抛出错误,并且测试仍然成功.

I have used an example from official ngrx docs https://ngrx.io/guide/effects/testing and now I can successfully enter the subscribe block below, I get both console logs logged, but the test succeeds. This is bizarre! I have tried throwing errors from the subscribe block and the test still succeeds.

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:

Ok, so I got it working. In order to successfully test whether a specific Angular service method is called from within NgRx effect, I wrapped a test case in an 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();
  });

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

I await effects.$fetchApisPaths.subscribe(); to block the execution and run test assertion in the next line.

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

Now when I try to run expect(true).toBe(false); to test whether the test fails, it properly fails.

问题中我的代码存在问题(例如ngrx文档 https:中的ReplaySubject示例: //ngrx.io/guide/effects/testing )是,当断言位于.subscribe()块中时,不可能使测试失败.那里有些疑惑,我仍然不知道为什么代码会以以下方式表现:

The problem with my code in the question (the example with ReplaySubject as in ngrx docs https://ngrx.io/guide/effects/testing ) was that it was not possible to fail a test when the assertion was inside .subscribe() block. Something iffy was going on in there and I still don't know exactly why the code was behaving in the following manner:

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)行永不执行.

So the code execution stops on line 2), test case returns positive and line 3) never gets executed.

因此,在.subscribe()块内有断言的ngrx docs中的测试用例将始终为绿色,这给您的测试用例带来了误判.这是我在ngrx ^7.0.0

So the test case in ngrx docs with assertion inside .subscribe() block will always be green, giving you a false positive for your test case. This is the behaviour I experienced with ngrx ^7.0.0

这篇关于单元测试NgRx效果以确保调用了服务方法-不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆