代码之家  ›  专栏  ›  技术社区  ›  codeepic zetriks

单元测试NGRX效果以确保调用服务方法-不工作

  •  0
  • codeepic zetriks  · 技术社区  · 5 年前

    我正在使用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上也有类似的问题 How to unit test this effect (with {dispatch: false})? 但它对我不起作用,好像代码执行从未进入效果。$fetchapaths.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 现在我可以成功地进入下面的subscribe块,记录两个控制台日志,但是测试成功。这太奇怪了!我尝试从订阅块抛出错误,测试仍然成功。

    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
        });
      });
    
    1 回复  |  直到 5 年前
        1
  •  0
  •   codeepic zetriks    5 年前

    好吧,我让它工作了。为了成功测试特定的角度服务方法是否在ngrx效果中被调用,我将一个测试用例包装在 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(); 阻止执行并在下一行运行测试断言。

    现在当我试着跑的时候 expect(true).toBe(false); 为了测试测试是否失败,它正确地失败了。

    问题中我的代码有问题(示例 ReplaySubject 在NGRX文档中 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文档中的测试用例 订阅() 块将始终是绿色的,给您的测试用例一个假阳性。这就是我经历过的行为 ngrx ^7.0.0