Angular 如何将 Subject() 作为 Observable 进行测试

Angular how to test a Subject() as an Observable

我的问题是我不知道如何在订阅主题的组件上测试订阅,我的代码是这样的:

实用服务:

private clearFlag = new Subject<boolean>();
public readonly message$ = this.clearFlag.asObservable();

getClearFlag(): Observable<boolean> {
  return this.message$;
}

setClearFlag(clear: boolean) {
  this.clearFlag.next(clear);
}

在组件中,我在 ngOnInit 方法中订阅了那个 Subject,像这样:

this.utilService.getClearFlag().subscribe((value) => {
      this.clearFlag = value;
    });

这个主题的值由另外两个组件给出,如下所示:

this.utilService.setClearFlag(false);

我需要测试代码的订阅片段,但我不确定如何,我已经尝试了 Whosebug 上的每一个解决方案,但我不断收到此错误:

Failed: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'subscribe')

规格文件:

describe('ContactsPageComponent', () => {
  let component: ContactsPageComponent;
  let fixture: ComponentFixture<ContactsPageComponent>;
  let utilServiceSpy: jasmine.SpyObj<UtilService>;
  let contactsHttpSpy: jasmine.SpyObj<ContactsHttpService>;
  let contactServiceSpy: jasmine.SpyObj<ContactService>;
  let qrSpy: jasmine.SpyObj<QrService>;
  let storeService: StorageService;
  // const clearFlag = new Subject<false>();


  beforeEach(
    waitForAsync(() => {
      utilServiceSpy = jasmine.createSpyObj('UtilService', [
        'getLoadingModal',
        'transactionStatus',
        'transactionStatusDescription',
        // 'getClearFlag',
        'setClearFlag',
      ]);

      ...

      TestBed.configureTestingModule({
        declarations: [ContactsPageComponent],
        imports: [
          IonicModule,
          CommonModule,
          HttpClientTestingModule,
          YpHeaderModule,
          RouterTestingModule,
          BrowserAnimationsModule,
          LottieModule,
        ],
        providers: [
          ...

          // { provide: UtilService, useValue: utilServiceSpy, clearFlag },

          { provide: UtilService, useValue: utilServiceSpy },

          ...

        ],
      }).compileComponents();


      fixture = TestBed.createComponent(ContactsPageComponent);
      component = fixture.componentInstance;
      component.clearFlag = false;

      fixture.detectChanges();

      const utilService = TestBed.inject(UtilService);

      // spyOn(utilService,'setClearFlag').and.returnValue();
      // spyOn(utilService,'setClearFlag').and.callFake(() => false);


      utilServiceSpy.setClearFlag(false);
      const spy = spyOn(utilService.message$, 'subscribe').and.callThrough();


      // const spy = jasmine.createSpyObj(UtilService, ['getClearFlag']);
      // utilServiceSpy.message$.subscribe(v => {
      //   expect(v).toBeDefined();
      // });
      // utilService.message$.subscribe(v => {
      //   expect(v).toBeDefined();
      // });

      component.ngOnInit();
      expect(component.clearFlag).toBeDefined();
      expect(spy).toHaveBeenCalled();
    })
  );

我把注释掉的代码留在那儿,这样你就可以看到我试过的解决方案。

试试这个:

import { of } from 'rxjs';
....
waitForAsync(() => {
      utilServiceSpy = jasmine.createSpyObj('UtilService', [
        'getLoadingModal',
        'transactionStatus',
        'transactionStatusDescription',
        // uncomment getClearFlag
        'getClearFlag',
        'setClearFlag',
      ]);
    
     ....
     fixture = TestBed.createComponent(ContactsPageComponent);
     component = fixture.componentInstance;
     component.clearFlag = false;
     // return whatever you would like here
     utilServiceSpy.getClearFlag.and.returnValue(of(true));
     // the first fixture.detectChanges will run ngOnInit
     fixture.detectChanges();
     expect(component.clearFlag).toBeTrue();

其他的我觉得还不错。