您应该存根onClickSaved、onClickCompleted 和onClickMarkedAsSpam 方法,这样它们就不会产生副作用。这样,我们就可以在隔离环境中测试_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);
});
});
单元测试结果: