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

运行ng test时触发Firebase Query.where()传入undefined值报错如何解决

报错原因

  1. 单元测试环境未模拟ActivatedRoute路由参数:组件ngOnInit生命周期中会读取路由参数id传入taskService.getTask()方法,测试环境下默认路由参数为空,params['id']为undefined,而getTask()内部调用Firestore的Query.where()方法时直接使用了该值,触发参数非法报错。
  2. 单元测试环境未模拟AngularFireAuth登录状态:测试环境默认没有登录用户,fire.user.subscribe拿到的用户对象为null,后续auth.getUserData(user?.uid)传入的uid为undefined,getUserData内部同样调用Query.where()查询用户数据时传入了空值。
  3. 组件代码缺少空值防御判断:没有对路由参数、用户对象做非空校验就直接传入Firebase查询方法,生产环境也可能出现同类报错。

修复方案

第一步:修改单元测试文件 task-settings.component.spec.ts,模拟依赖项

不需要在单元测试中引入真实的Firebase模块,直接Mock所有外部依赖即可:

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { ActivatedRoute, Params } from '@angular/router';
import { AngularFireAuth } from '@angular/fire/auth';
import { of } from 'rxjs';
import { TaskSettingsComponent } from './task-settings.component';
import { AuthService } from 'src/app/services/auth.service';
import { TaskService } from 'src/app/services/task.service';
import { ToastService } from 'src/app/services/toast.service';

// Mock所有外部服务
class MockAuthService {
  getUserData = (uid: string) => of({ uid, name: '测试用户' });
}
class MockTaskService {
  getTask = (id: string) => of({
    taskId: id,
    title: '测试任务',
    description: '测试描述',
    deadline: new Date(),
    recipients: []
  });
  updateTask = () => Promise.resolve();
  deleteTask = () => Promise.resolve();
}
class MockToastService {
  publish = () => {};
}

describe('TaskSettingsComponent', () => {
  let component: TaskSettingsComponent;
  let fixture: ComponentFixture<TaskSettingsComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ TaskSettingsComponent ],
      imports: [ RouterTestingModule, ReactiveFormsModule, FormsModule ],
      providers: [
        FormBuilder,
        { provide: AuthService, useClass: MockAuthService },
        { provide: TaskService, useClass: MockTaskService },
        { provide: ToastService, useClass: MockToastService },
        // 模拟ActivatedRoute参数
        {
          provide: ActivatedRoute,
          useValue: {
            params: of<Params>({ id: 'test-task-123' })
          }
        },
        // 模拟AngularFireAuth登录用户
        {
          provide: AngularFireAuth,
          useValue: {
            user: of({ uid: 'test-user-123' })
          }
        }
      ]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(TaskSettingsComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

第二步:修改组件代码 task-settings.component.ts,增加空值防御

// 修改ngOnInit内的相关逻辑,增加非空判断
ngOnInit(): void {
  // 原有term计算逻辑保留...
  this.updateTaskForm = this.fb.group({
    title: ['', Validators.required],
    description: ['', Validators.required],
    deadline: ['', Validators.required],
  });
  this.fire.user.subscribe((user: any) => {
    // 增加用户非空判断
    if (user?.uid) {
      this.userData = user;
      this.auth.getUserData(user.uid).subscribe((res) => {
        this.fsData = res;
      });
    }
  });
  this.route.params
    .pipe(
      switchMap((params: Params) => {
        console.log(params['id']);
        // 增加路由id非空判断
        if (params['id']) {
          return this.taskService.getTask(params['id']);
        }
        // 没有id时返回空流
        return of(null);
      })
    )
    .subscribe((res) => {
      // 结果非空才赋值
      if (res) {
        this.updateTaskForm.controls.title.setValue(res.title);
        this.updateTaskForm.controls.description.setValue(res.description);
        this.updateTaskForm.controls.deadline.setValue(res.deadline);
        this.taskData = res;
        console.log(res);
      }
    });
  this.taskScopeArray = [];
}

修改后单元测试不会再调用真实Firebase服务,同时组件也具备了空值防御能力,不会再触发该类参数错误。

内容的提问来源于stack exchange,提问作者Tootsie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 07:09:03