【问题标题】:Jasmine, how to test observable method logic?Jasmine,如何测试可观察的方法逻辑?
【发布时间】:2021-03-25 05:56:22
【问题描述】:

onMessageActionTriggered$ 发出新值时,在switch/case 块中调用this.onClickSaved() 方法多少次的正确解决方案是什么?

// 服务

export class WebMessageService {
  private _onMessageActionTriggered = new BehaviorSubject<ITriggerMessageAction>(undefined);
  get onMessageActionTriggered$(): Observable<ITriggerMessageAction> {
    return this._onMessageActionTriggered.asObservable();
  }

  triggerMessageAction(actionDto: ITriggerMessageAction) {
    this._onMessageActionTriggered.next(actionDto);
  }          
}

// 组件

export class MessageComponent{
  ngOnInit() {
    this._subscribeToActionsFromConversationHeader();
  }

  private _subscribeToActionsFromConversationHeader() {
    this.subscriptions.push(
      this._messageService.onMessageActionTriggered$
        .pipe(filter(dto => dto?.messageId === this.model.id && dto?.streamId === this.stream.streamId))
        .subscribe(dto => {
          switch (dto.newState) {
            case WebcareState.Saved: {
              this.onClickSaved();
              break;
            }
            case WebcareState.Completed: {
              this.onClickCompleted();
              break;
            }
            case WebcareState.MarkedAsSpam: {
              this.onClickMarkedAsSpam();
              break;
            }
          }
        })
    );
  }
}

【问题讨论】:

标签: angular typescript rxjs jasmine angular-test


【解决方案1】:

您应该存根onClickSavedonClickCompletedonClickMarkedAsSpam 方法,这样它们就不会产生副作用。这样,我们就可以在隔离环境中测试_subscribeToActionsFromConversationHeader方法了。您应该在发出值之前通过调用messagService.triggerMessageAction() 方法对它们进行存根。

例如使用angular v11+:

message.component.ts:

import { Component } from '@angular/core';
import { filter } from 'rxjs/operators';
import { WebcareState, WebMessageService } from './message.service';

@Component({
  selector: 'app-message',
  template: '<span>message component</span>',
})
export class MessageComponent {
  subscriptions = [];
  model = { id: '1' };
  stream = { streamId: '1' };

  constructor(private _messageService: WebMessageService) {}

  ngOnInit() {
    this._subscribeToActionsFromConversationHeader();
  }

  onClickSaved() {}
  onClickCompleted() {}
  onClickMarkedAsSpam() {}

  private _subscribeToActionsFromConversationHeader() {
    this.subscriptions.push(
      this._messageService.onMessageActionTriggered$
        .pipe(
          filter(
            (dto) =>
              dto?.messageId === this.model.id &&
              dto?.streamId === this.stream.streamId
          )
        )
        .subscribe((dto) => {
          switch (dto.newState) {
            case WebcareState.Saved: {
              this.onClickSaved();
              break;
            }
            case WebcareState.Completed: {
              this.onClickCompleted();
              break;
            }
            case WebcareState.MarkedAsSpam: {
              this.onClickMarkedAsSpam();
              break;
            }
          }
        })
    );
  }
}

message.service.ts:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

export enum WebcareState {
  Saved = 'Saved',
  Completed = 'Completed',
  MarkedAsSpam = 'MarkedAsSpam',
}

export interface ITriggerMessageAction {
  messageId?: string;
  streamId?: string;
  newState: WebcareState;
}

@Injectable()
export class WebMessageService {
  private _onMessageActionTriggered = new BehaviorSubject<ITriggerMessageAction>(
    undefined
  );
  get onMessageActionTriggered$(): Observable<ITriggerMessageAction> {
    return this._onMessageActionTriggered.asObservable();
  }

  triggerMessageAction(actionDto: ITriggerMessageAction) {
    this._onMessageActionTriggered.next(actionDto);
  }
}

message.component.spec.ts:

import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { MessageComponent } from './message.component';
import {
  ITriggerMessageAction,
  WebcareState,
  WebMessageService,
} from './message.service';

fdescribe('65291642', () => {
  let fixture: ComponentFixture<MessageComponent>;
  let component: MessageComponent;
  let messageService: WebMessageService;
  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        declarations: [MessageComponent],
        providers: [WebMessageService],
      })
        .compileComponents()
        .then(() => {
          fixture = TestBed.createComponent(MessageComponent);
          component = fixture.componentInstance;
          messageService = TestBed.inject(WebMessageService);
        });
    })
  );

  it('should handle click saved', () => {
    const testAction: ITriggerMessageAction = {
      messageId: '1',
      streamId: '1',
      newState: WebcareState.Saved,
    };

    const onClickSavedSpy = spyOn(component, 'onClickSaved').and.stub();
    messageService.triggerMessageAction(testAction);
    fixture.detectChanges();
    expect(onClickSavedSpy).toHaveBeenCalled();
    expect(component.subscriptions).toHaveSize(1);
  });

  it('should handle click completed', () => {
    const testAction: ITriggerMessageAction = {
      messageId: '1',
      streamId: '1',
      newState: WebcareState.Completed,
    };

    const onClickCompletedSpy = spyOn(component, 'onClickCompleted').and.stub();
    messageService.triggerMessageAction(testAction);
    fixture.detectChanges();
    expect(onClickCompletedSpy).toHaveBeenCalled();
    expect(component.subscriptions).toHaveSize(1);
  });

  it('should handle click completed', () => {
    const testAction: ITriggerMessageAction = {
      messageId: '1',
      streamId: '1',
      newState: WebcareState.MarkedAsSpam,
    };

    const onClickMarkedAsSpamSpy = spyOn(
      component,
      'onClickMarkedAsSpam'
    ).and.stub();
    messageService.triggerMessageAction(testAction);
    fixture.detectChanges();
    expect(onClickMarkedAsSpamSpy).toHaveBeenCalled();
    expect(component.subscriptions).toHaveSize(1);
  });
});

单元测试结果:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 2020-02-25
    • 1970-01-01
    • 2016-06-10
    • 2018-08-31
    • 2018-12-11
    • 1970-01-01
    相关资源
    最近更新 更多