You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。

正确操作步骤:

  1. 先修改AngularFireAuthMock的authState返回值(用spyOnProperty返回of(null))
  2. 再实例化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 05:26:16