【问题标题】:Mocking a Subject property of mocked service to be subscribed in the Angular unit test模拟要在 Angular 单元测试中订阅的模拟服务的主题属性
【发布时间】:2021-04-23 02:57:26
【问题描述】:

在我的 Angular 单元测试中,我的模拟服务有两个属性:

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

在我的 SUT 中,我在构造函数中使用它们:

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);
    });

现在我正在尝试使用这两种方法来模拟来自模拟服务的属性:

现在我的测试看起来像这样:

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();
  });
}

所以在我创建的测试中:

  • 服务模拟hubServiceMock,

  • messageChange = new Subject();

  • gameChange = new Subject();

  • 我为.next 竞选,

  • 我为属性设置了间谍:

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

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

为什么它对我不起作用?我收到一个错误:

无法读取未定义的属性“订阅”

【问题讨论】:

    标签: angular unit-testing properties jasmine subject


    【解决方案1】:

    它不起作用,因为hubServiceMock 在其messageChangegameChange 中没有虚假主题,您需要在调用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;
    

    那么它应该可以工作,也许需要进行一些小调整。


    我建议在这种情况下使用模拟库以避免痛苦。

    例如使用ng-mocks,测试可能如下所示:

    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.
      });
    }
    

    【讨论】:

    • 我最终采用了上述方法,它看起来工作正常。您对此有何看法?
    • 最主要的是它适合你。编写测试的方法有很多种。
    【解决方案2】:

    我最终采用了这样的方法,在那里我注入了这样的模拟服务:

    hubServiceMock = TestBed.inject(HubConnectionService);
    

    然后我像这样嘲笑我的Subjects:

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

    在其他测试中,我可以使用类似的模拟服务方法:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-03
      • 2018-12-13
      • 2019-08-12
      • 2020-04-19
      • 2021-09-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多