Angular中Jest单元测试异常:Observable属性订阅无值但方法形式正常
问题原因
你的currentContent$是类的实例属性,在TestService实例创建的瞬间就会执行this.getContent()并初始化这个Observable。而你是先创建了service实例,再用jest.spyOn去mockgetContent方法——这时候currentContent$已经绑定了原始getContent返回的Observable,mock根本没作用到它身上,所以订阅自然收不到值。
而testMethod()是调用时才执行this.getContent(),这时候mock已经生效,所以能正常拿到mock的Observable,订阅就有输出。
解决方案
方案1:先mock方法,再创建服务实例
把mock操作放在实例化service之前,这样初始化currentContent$时就会用mock后的getContent:
it('should emit values only if not deeply equal', () => { const mockData1 = {value:'Path1'}; const mockData2 = {value:'Path2'}; const mockData3 = {value:'Path3'}; // 先mock原型上的getContent方法 jest.spyOn(TestService.prototype, 'getContent').mockReturnValue(of(mockData1, mockData2, mockData3, mockData3)); // 再创建service实例 const service = new TestService(); const emittedValues: any[] = []; service.currentContent$.subscribe((value) => { emittedValues.push(value); }); // of是同步Observable,直接断言即可,无需setTimeout和done expect(emittedValues).toEqual([mockData1, mockData2, mockData3]); });
方案2:将currentContent$改为getter延迟初始化
修改TestService,把currentContent$改成getter属性,这样每次访问它时才会调用getContent(),mock后再访问就会生效:
export class TestService { // 改成getter get currentContent$(): Observable<any> { return this.getContent().pipe( distinctUntilChanged((p, c) => isEqual(p, c)) ); } constructor() {} getContent(): Observable<any> { return of('some test return value'); } }
测试代码可以保持你原来的顺序(先实例化,再mock,再订阅):
it('should emit values only if not deeply equal', () => { const service = new TestService(); const mockData1 = {value:'Path1'}; const mockData2 = {value:'Path2'}; const mockData3 = {value:'Path3'}; jest.spyOn(service, 'getContent').mockReturnValue(of(mockData1, mockData2, mockData3, mockData3)); const emittedValues: any[] = []; service.currentContent$.subscribe((value) => { emittedValues.push(value); }); expect(emittedValues).toEqual([mockData1, mockData2, mockData3]); });
额外注意点
- 原测试里的断言错误:你mock的是
{value:'Path1'}这类对象,所以断言应该匹配对象数组,而不是字符串数组['Path1','Path2','Path3'];如果要断言value字段,订阅时可以pushvalue.value。 of创建的Observable是同步发射值的,完全不需要用setTimeout和done,直接订阅后就能断言。
内容的提问来源于stack exchange,提问作者Smita
相关产品推荐
相关产品推荐

