模拟要在 Angular 单元测试中订阅的模拟服务的主题 属性
Mocking a Subject property of mocked service to be subscribed in the Angular unit test
在我的 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);
});
现在我正在尝试使用这两种方法来模拟来自模拟服务的属性:
- How to spyOn a value property (rather than a method) with Jasmine
现在我的测试是这样的:
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();
,
i 运行 .next
,
并且我为属性设置了间谍:
spyOnProperty(hubServiceMock, 'messageChange', 'get').and.returnValue( messageChange );
spyOnProperty(hubServiceMock, 'gameChange', 'get').and.returnValue( gameChange );
为什么对我不起作用?我收到一个错误:
Cannot read property 'subscribe' of undefined
它不起作用,因为 hubServiceMock
在其 messageChange
和 gameChange
中没有假主题,您需要在调用 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.
});
}
我最终采用了一种方法,我像这样注入模拟服务:
hubServiceMock = TestBed.inject(HubConnectionService);
然后我这样嘲笑我的 Subject
s:
it('Service_ShouldBeCreated', () => {
spyOn(hubServiceMock.messageChange, 'next');
spyOn(hubServiceMock.gameChange, 'next');
expect(signalrService).toBeTruthy();
});
在其他测试中,我可以使用这样的模拟服务方法:
let spyIsConnectionStarted = spyOn(hubServiceMock, 'isConnectionStarted');
spyIsConnectionStarted.and.returnValue(true);
在我的 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);
});
现在我正在尝试使用这两种方法来模拟来自模拟服务的属性:
- How to spyOn a value property (rather than a method) with Jasmine
现在我的测试是这样的:
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();
,i 运行
.next
,并且我为属性设置了间谍:
spyOnProperty(hubServiceMock, 'messageChange', 'get').and.returnValue( messageChange );
spyOnProperty(hubServiceMock, 'gameChange', 'get').and.returnValue( gameChange );
为什么对我不起作用?我收到一个错误:
Cannot read property 'subscribe' of undefined
它不起作用,因为 hubServiceMock
在其 messageChange
和 gameChange
中没有假主题,您需要在调用 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.
});
}
我最终采用了一种方法,我像这样注入模拟服务:
hubServiceMock = TestBed.inject(HubConnectionService);
然后我这样嘲笑我的 Subject
s:
it('Service_ShouldBeCreated', () => {
spyOn(hubServiceMock.messageChange, 'next');
spyOn(hubServiceMock.gameChange, 'next');
expect(signalrService).toBeTruthy();
});
在其他测试中,我可以使用这样的模拟服务方法:
let spyIsConnectionStarted = spyOn(hubServiceMock, 'isConnectionStarted');
spyIsConnectionStarted.and.returnValue(true);