Burlarse de una propiedad de sujeto del servicio simulado para suscribirse en la prueba de unidad angular
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
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.
  });
}
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);