Burlarse de una propiedad de sujeto del servicio simulado para suscribirse en la prueba de unidad angular

Jan 19 2021

En mi prueba de unidad angular, mi servicio simulado tiene dos propiedades:

  public messageChange: Subject<ChatMessage> = new Subject<ChatMessage>();
  public gameChange: Subject<GameState> = new Subject<GameState>();

Y en mi SUT los uso en mi constructor:

this._subChat = this.hub.messageChange.subscribe((message: ChatMessage) => {
      this.message = message;
      this.messageChange.next(this.message);
    });
    this._subGame = this.hub.gameChange.subscribe((game: GameState) => {
      this.game.setGame(game);
    });

En este momento estoy tratando de usar estos 2 enfoques para simular propiedades del servicio simulado:

  • Asunto de reproducción simulada de prueba de unidad angular
  • Cómo espiar una propiedad de valor (en lugar de un método) con Jasmine

Ahora mi prueba se ve así:

describe('SignalRService', () => {
  let signalrService: SignalRService;
  const hubServiceMock = jasmine.createSpyObj('HubConnectionService', [
    'isConnectionStarted',
  ]);
  const messageChange = new Subject();
  const gameChange = new Subject();

  beforeEach(() => {
    signalrService = new SignalRService(
      hubServiceMock
    );
    let msg = {} as ChatMessage;
    let gam = {} as GameState;
    messageChange.next(msg);
    gameChange.next(gam);
  });

  it('Service_ShouldBeCreated', () => {
    spyOnProperty(hubServiceMock, 'messageChange', 'get').and.returnValue(
      messageChange
    );
    spyOnProperty(hubServiceMock, 'gameChange', 'get').and.returnValue(
      gameChange
    );
    expect(signalrService).toBeTruthy();
  });
}

Entonces en la prueba creo:

  • simulacro de servicio hubServiceMock,

  • falso messageChange = new Subject();,

  • falso gameChange = new Subject();,

  • corro por los dos .next,

  • y configuro espía para propiedades:

    spyOnProperty(hubServiceMock, 'messageChange', 'get').and.returnValue( messageChange );

    spyOnProperty(hubServiceMock, 'gameChange', 'get').and.returnValue( gameChange );

¿Por qué no me funciona? Recibo un error:

No se puede leer la propiedad 'subscribe' de undefined

Respuestas

1 satanTime Jan 19 2021 at 13:37

No funciona porque hubServiceMockno tiene los sujetos falsos en su messageChangey gameChange, debe configurarlos antes de llamar new SignalRService(hubServiceMock).

  const hubServiceMock = jasmine.createSpyObj('HubConnectionService', [
    'isConnectionStarted',
  ]);
  const messageChange = new Subject();
  const gameChange = new Subject();

  // add this
  hubServiceMock.messageChange = messageChange;
  hubServiceMock.gameChange = gameChange;

entonces debería funcionar, tal vez se necesiten pequeños ajustes.


Sugeriría usar una biblioteca burlona para tales casos para evitar el dolor.

Por ejemplo, con ng-mocks , la prueba podría verse así:

describe('SignalRService', () => {
  beforeEach(() => MockBuilder(SignalRService, ITS_MODULE));

  const hubServiceMock = {
    messageChange: new Subject(),
    gameChange: new Subject(),
  };
  beforeEach(() => MockInstance(HubConnectionService, hubServiceMock));


  it('Service_ShouldBeCreated', () => {
    const signalrService = MockRender(SignalRService).point.componentInstance;
    expect(signalrService).toBeTruthy();

    hubServiceMock.messageChange.next({});
    hubServiceMock.gameChange.next({});
    // next assertions.
  });
}
1 bakunet Jan 19 2021 at 14:29

Terminé con el enfoque, donde inyecto un servicio simulado como este:

hubServiceMock = TestBed.inject(HubConnectionService);

Entonces me burlo de mis Subjects así:

it('Service_ShouldBeCreated', () => {
    spyOn(hubServiceMock.messageChange, 'next');
    spyOn(hubServiceMock.gameChange, 'next');
    expect(signalrService).toBeTruthy();
  });

Y en otras pruebas puedo usar métodos de servicio simulado como ese:

let spyIsConnectionStarted = spyOn(hubServiceMock, 'isConnectionStarted');
    spyIsConnectionStarted.and.returnValue(true);