【问题标题】:Angular NgRx integration test not working (with Nx and Jest)Angular NgRx 集成测试不起作用(使用 Nx 和 Jest)
【发布时间】:2021-03-02 00:36:11
【问题描述】:

我有一个在幕后使用 NgRx 的外观类。当我在我的应用程序中使用它时,外观本身正在工作,但是通过集成测试它不起作用(更好的说法是:测试不起作用)。我正在使用 Nx(不认为这很重要)和 Jest。

注意:集成测试的意思是我不想模拟 NgRx 部分,我也想测试 NgRx 逻辑。只有数据服务被模拟。

外观类非常简单。这是它的摘录:

@Injectable({
  providedIn: 'root'
})
export class ProfileFacade {
  public isProfileLoaded$ = this.store.select(Selectors.isProfileLoaded);

  public constructor(private store: Store<fromProfile.PartialState>) {
    /* */
  }

  public loadProfile(): void {
    this.dispatch(Actions.loadProfile());
  }

  private dispatch(action: Action): void {
    this.store.dispatch(action);
  }
}

dipatched loadProfile 操作会触发一个效果,该效果会返回包含通过 ProfileService 获取的数据的 ProfileLoadSucceeded 操作。然后,reducer 捕获此操作,将配置文件数据放入存储中,并将 isProfileLoaded 属性设置为 true。

这是我的集成测试的设置:

describe('ProfileFacade integration', () => {
  let facade: ProfileFacade;
  let store: Store<fromProfile.PartialState>;
  let profileServiceSpy: SpyObject<ProfileService>;

  beforeEach(() => {
    @NgModule({
      imports: [
        StoreModule.forFeature(fromProfile.PROFILE_FEATURE_KEY, fromProfile.reducer),
        EffectsModule.forFeature([ProfileEffects])
      ],
      providers: [
        ProfileFacade,
        mockProvider(ProfileService),
      ]
    })
    class CustomFeatureModule {}

    @NgModule({
      imports: [NxModule.forRoot(), StoreModule.forRoot({}), EffectsModule.forRoot([]), CustomFeatureModule]
    })
    class RootModule {}
    TestBed.configureTestingModule({ imports: [RootModule] });

    store = TestBed.inject(Store);
    facade = TestBed.inject(ProfileFacade);
    profileServiceSpy = TestBed.inject(ProfileService) as SpyObject<ProfileService>;
  });

  ...
});

以下是我在集成测试中尝试过的许多事情的选择:

  1. 使用 expect(...).toBeObservable(...)

      it(`should set isProfileLoaded to true`, () => {
        profileServiceSpy.get.and.returnValue(hot('^x|', { x: profile }));  // I've tried several variations of hot and cold
        facade.loadProfile();
    
        const expected = cold('--b', { b: true });
        expect(facade.isProfileLoaded$).toBeObservable(expected);
      });
    
  2. 使用 toPromise() 和 then()

      it(`should set isProfileLoaded to true`, () => {
        // same 2 lines as in 1)
    
        return facade.isProfileLoaded$.toPromise().then(result => expect(result).toBe(true));
      });
    
  3. 用expect(...toPromise()).resolves()

      it(`should set isProfileLoaded to true`, () => {
        // same 2 lines as in 1)
    
        return expect(facade.isProfileLoaded$.toPromise()).resolves.toBe(true);
      });
    
  4. 使用 subscribe 和 done()

      it(`should set isProfileLoaded to true`, done => {
        // same 2 lines as in 1)
    
        facade.isProfileLoaded$.subscribe(result => {
          expect(result).toBe(true);
          done();
        });
      });
    

我只是展示了 isProfileLoaded 的测试,但我对数据本身的测试也有同样的问题。结果值始终为 false 或 null:外观的选择器结果似乎没有反映商店的内容。

不过,商店本身似乎运作良好。通过在不同的地方添加 console.log 语句,我可以看到来自模拟服务的数据正在正常流动。它存在于效果、reducer 和结果状态中。

我想我遗漏了一些明显的东西,但是什么?我还没有找到使用这种技术组合执行这种集成测试的示例。

【问题讨论】:

    标签: angular jestjs integration-testing ngrx jasmine-marbles


    【解决方案1】:

    由于您已经在使用 Nx,我能想到的一种方法是:

    import { readFirst } from '@nrwl/nx/testing';
    
    it(`should set isProfileLoaded to true`, async (done) => {
      try {
        profileServiceSpy.get.and.returnValue(of(profile));
    
        facade.loadProfile();
    
        const isProfileLoaded = await readFirst(facade.isProfileLoaded$);
    
        expect(isProfileLoaded).toBeTruthy();
    
        done();
      } catch (error) {
        done.fail(error);
      }
    });
    

    【讨论】:

    • 非常感谢,async、done() 和 readFirst 的组合可以解决问题!有点麻烦,但至少它有效。我不明白为什么更直接(更少代码)的方法不起作用。
    • 好的,我可以通过让测试返回一个承诺来稍微简化代码。像那样我不需要 try/catch 和 done() 调用。像这样:it('...', () =&gt; { profileServiceSpy.get.and.returnValue(of(profile)); facade.loadProfile(); return expect(readFirst(facade.isProfileLoaded$)).resolves.toBeTruthy(); }); 我会将此解决方案添加到我的问题中,以使其更具可读性。再次感谢 lito!
    猜你喜欢
    • 2022-08-23
    • 2019-02-28
    • 1970-01-01
    • 2020-08-13
    • 2020-06-14
    • 1970-01-01
    • 2018-11-24
    • 2019-02-06
    • 2013-10-21
    相关资源
    最近更新 更多