angular - 为什么 Angular 单元测试没有测试此服务中的订阅内容?

标签 angular typescript angular2-observables angular2-testing karma-coverage

我正在使用 Angular 14。我正在尝试测试此服务:

import { EnvironmentService } from './environment.service';
import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
import { InteractionStatus, RedirectRequest, EventMessage, EventType } from '@azure/msal-browser';
import { Subject, filter, takeUntil } from 'rxjs';
import { Inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

const GRAPH_ENDPOINT = 'https://graph.microsoft.com/v1.0/me';

/**
 * Every method is disabled if the environment is for development
 */
@Injectable({
  providedIn: 'root'
})
export class AuthenticationService {

  public isIframe: boolean = false;
  public loginDisplay: boolean = !this._environmentService.getEnvironment().production;
  public userLogged$: Subject<boolean> = new Subject<boolean>();
  private readonly _destroying$ = new Subject<void>();
  public profile: any = {
    displayName: "Dev Mode User"
  };

  constructor(
    @Inject(MSAL_GUARD_CONFIG) private _msalGuardConfig: MsalGuardConfiguration,
    private _msalService: MsalService,
    private _msalBroadcastService: MsalBroadcastService,
    private _httpClient: HttpClient,
    private _environmentService: EnvironmentService
  ) { }

  /**
   * Send thorugh observable the information if the user logged or not
   */
  setLoginDisplay() {
    console.log("setLoginDisplay called");
  }

  /**
   * Redirec to login display
   */
  loginRedirect(): void {
    if (this._environmentService.getEnvironment().production) {
      this._msalService.loginRedirect().subscribe(
        () => {
          this.setLoginDisplay();
        }
      );
    }
  }

}

在其他情况下,可观察对象是依赖项的属性,它可以工作,但由于某种原因在这里不起作用,因为我不断收到此错误:预期 spy setLoginDisplay 已被调用。。 通过检查覆盖范围,我注意到测试没有考虑订阅的内容: enter image description here

这是我尝试过的相应的spec.ts文件:

import { EnvironmentService } from './environment.service';
import { Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG } from '@azure/msal-angular';
import { MockService } from 'ng-mocks';
import { TestBed, tick } from '@angular/core/testing';

import { AuthenticationService } from './authentication.service';
import { AccountInfo, EventMessage, InteractionStatus } from '@azure/msal-browser';

const mockInstance: any = {
  enableAccountStorageEvents(): void { },
  getAllAccounts(): AccountInfo[] { return [] },
  getActiveAccount(): AccountInfo | null { return null },
  setActiveAccount(account: AccountInfo | null): void { }
}


describe('AuthenticationService', () => {
  let service: AuthenticationService;

  const mockMsalService = MockService(MsalService, {
    instance: mockInstance
  });
  const mockMsalBroadcastService = MockService(MsalBroadcastService, {
    msalSubject$: new Observable<EventMessage>(),
    inProgress$: new Observable<InteractionStatus>(),
  });
  const mockHttpClient = MockService(HttpClient);
  const mockEnvironmentService = MockService(EnvironmentService, {
    getEnvironment() { return { production: true } }
  });

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        {
          provide: EnvironmentService,
          useValue: mockEnvironmentService
        },
        {
          provide: MsalService,
          useValue: mockMsalService
        },
        {
          provide: MsalBroadcastService,
          useValue: mockMsalBroadcastService
        },
        {
          provide: HttpClient,
          useValue: mockHttpClient
        },
        {
          provide: MSAL_GUARD_CONFIG,
          useValue: {}
        }
      ]
    });

    mockMsalBroadcastService.msalSubject$ = new Observable<EventMessage>();
    mockMsalBroadcastService.inProgress$ = new Observable<InteractionStatus>();
  });

  it('should call setLoginDisplay', fakeAsync(() => {
    service = TestBed.inject(AuthenticationService);
    const setLoginDisplaySpy = spyOn(service, "setLoginDisplay").and.callFake(() => { });
    const loginRedirectSpy = spyOn(mockMsalService, "loginRedirect").and.returnValue(new Observable<void>());
    service.loginRedirect();
    tick();
    expect(setLoginDisplaySpy).toHaveBeenCalled();

  }));


});

有人可以帮助我并向我解释为什么会发生这种情况吗? 先感谢您! ^^

最佳答案

我认为您所监视的 mockMsalService 中的 new Observable() 不会发出任何值。因此,即使您等待一个tick,您的订阅也永远不会执行。 您可能需要使用 of(undefined)of({}) 来代替:

const loginRedirectSpy = spyOn(mockMsalService, "loginRedirect").and.returnValue(of(undefined));

由于 of 同步工作,您甚至可以从测试中删除 tick()

关于angular - 为什么 Angular 单元测试没有测试此服务中的订阅内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75161312/

相关文章:

angular - Angular 6中的FontAwesome图标?

angular - 在 Angular 和 rxjs 中重新连接 websocket?

angular - 服务通知的组件

angular - 在 Angular Interceptors 中获取当前路线

angular - 在Nginx Ingress AKS上设置Angular应用程序

javascript - 在 Angular 中将对象插入数组

reactjs - Typescript 3.6 中的默认类型参数和默认参数

javascript - Angular 2 - 未捕获( promise ): RangeError: Maximum call stack size exceeded

angular2/RxJS - 如何从 subscribe() 内部重试

angular - 如何使用 Observables Angular 4.x 监控 http 请求的持续时间