Angular单元测试:Service构造函数未读取spyOnProperty模拟值问题
问题描述
我要给AuthService编写负面测试,验证当angularFireAuth未返回数据时,构造函数中的userData属性会被设置为null。正向测试已正常运行,直接修改mock文件可得到预期结果;但使用spyOnProperty模拟时,订阅后控制台日志显示返回null,可AuthService构造函数无法读取该spyOnProperty的返回值。组件测试可以用fixture.detectChanges,但这对服务测试无效。是否需要重新构建服务,才能让构造函数获取到模拟的null值?
AuthService 构造函数
{ (this.partyCollectionPath); this.afAuth.authState.subscribe((user: User | null) => { if (user) { this.userData = { uid: user.uid, email: user.email, emailVerified: user.emailVerified }; this.liveUid = user.uid } else { this.userData = null } }); }
AngularFireAuthMock 代码
import { User } from '../shared/interface/user'; import { of } from 'rxjs'; const authState: User = { uid: 'fakeuser', email: 'test@test.com', emailVerified: true }; export const AngularFireAuthMock: any = { AngularFireAuth: jasmine.createSpyObj('AngularFireAuth', { // other functions }), get authState() { return of(authState); }, };
测试断言代码
it('userData set to null', () => { const spy = spyOnProperty(AngularFireAuthMock, 'authState', 'get'); spy.and.returnValue(of(null)) AngularFireAuthMock.authState.subscribe((data: any) => { console.log('subscribe: ', data) }) console.log('userData: ', service.userData) // expect(service.userData).toBeNull() });
控制台日志
LOG: 'subscribe: ', null
LOG: 'userData: ', Object{uid: 'fakeuser', email: 'test@test.com', emailVerified: true}
解决方案
问题核心是服务实例化时机错误:你先创建了AuthService实例,之后才去spy authState属性,此时构造函数已经执行完毕,订阅的是原始mock的authState值,自然拿不到后续模拟的null。
正确操作步骤:
- 先修改AngularFireAuthMock的authState返回值(用spyOnProperty返回of(null))
- 再实例化AuthService(或在TestBed中重新配置依赖后获取服务实例)
修改后的测试代码(TestBed场景)
it('userData set to null', () => { // 先替换authState的返回值 const spy = spyOnProperty(AngularFireAuthMock, 'authState', 'get'); spy.and.returnValue(of(null)); // 重新获取服务实例,确保构造函数使用修改后的mock service = TestBed.inject(AuthService); // of是同步Observable,无需异步等待,直接断言 expect(service.userData).toBeNull(); });
修改后的测试代码(手动实例化场景)
it('userData set to null', () => { const spy = spyOnProperty(AngularFireAuthMock, 'authState', 'get'); spy.and.returnValue(of(null)); // 手动实例化服务,确保构造函数订阅的是已修改的authState const service = new AuthService(AngularFireAuthMock, /* 传入其他必要依赖 */); expect(service.userData).toBeNull(); });
关键逻辑:服务的构造函数只会在实例化时执行一次,必须在实例化服务之前完成对依赖的mock修改,这样构造函数中的subscribe才能捕获到你模拟的null值。
内容的提问来源于stack exchange,提问作者Rusty Shackleford
相关产品推荐
相关产品推荐

