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

Angular单元测试:如何Mock并注入带依赖的rxfire httpsCallable函数

Angular单元测试:Mock RxFire的httpsCallable及Firebase Functions依赖

问题根源

你碰到的functionInstance._url is not a function错误,核心原因是组件依赖的this.functions是真实Firebase Functions实例,即便Mock了httpsCallable,它内部仍会调用实例的私有方法(如_url)。另外,你用spyOnPropertyMock导出函数的方式有误,httpsCallable是rxfire模块导出的函数,并非属性。

正确实现方案

1. 先Mock Firebase Functions实例

在测试模块中提供Mock的Functions对象,规避真实实例的内部方法调用:

import { Functions } from '@angular/fire/functions';

// 创建Mock Functions对象,模拟所需私有方法/属性
const mockFunctions = jasmine.createSpyObj('Functions', [], {
  _url: jasmine.createSpy().and.returnValue('mock-api-endpoint-url')
});

beforeEach(async () => {
  await TestBed.configureTestingModule({
    declarations: [YourTargetComponent],
    providers: [
      // 注入Mock的Functions实例
      { provide: Functions, useValue: mockFunctions }
    ]
  }).compileComponents();
});

2. 正确Mock RxFire的httpsCallable函数

httpsCallable是模块导出的函数,需用spyOnMock整个模块的导出成员:

import * as rxfire from 'rxfire';
import { of } from 'rxjs';

beforeEach(() => {
  // 重置Spy,避免测试用例间状态污染
  spyOn(rxfire, 'httpsCallable').and.callFake(() => {
    // 返回模拟的可调用函数,支持接收参数并返回Observable
    return (formData: any) => {
      // 默认返回成功响应,后续可按需修改
      return of({ message: '表单提交成功' });
    };
  });
});

3. 编写多场景测试用例

测试成功响应场景

it('调用saveForm时应打印成功响应', () => {
  spyOn(console, 'log');
  const fixture = TestBed.createComponent(YourTargetComponent);
  const component = fixture.componentInstance;
  
  component.saveForm({ username: 'test', email: 'test@example.com' });
  
  // 验证控制台打印成功响应
  expect(console.log).toHaveBeenCalledWith({ message: '表单提交成功' });
  // 验证httpsCallable被传入正确参数调用
  expect(rxfire.httpsCallable).toHaveBeenCalledWith(mockFunctions, 'api/endpoint');
});

测试错误响应场景

临时修改httpsCallable的返回值为错误Observable:

import { throwError } from 'rxjs';

it('当接口调用失败时应打印错误信息', () => {
  spyOn(console, 'log');
  const fixture = TestBed.createComponent(YourTargetComponent);
  const component = fixture.componentInstance;
  
  // 覆盖默认Spy,返回错误Observable
  spyOn(rxfire, 'httpsCallable').and.callFake(() => {
    return (formData: any) => {
      return throwError(() => new Error('权限不足,无法提交'));
    };
  });
  
  component.saveForm({ username: 'test', email: 'test@example.com' });
  
  expect(console.log).toHaveBeenCalledWith(new Error('权限不足,无法提交'));
});

4. 可选:封装Mock工具函数

若多个测试用例需要重复Mock,可封装成工具函数提升复用性:

import { of, throwError } from 'rxjs';
import * as rxfire from 'rxfire';

function mockHttpsCallable(response: any | Error) {
  spyOn(rxfire, 'httpsCallable').and.callFake(() => {
    return (data: any) => {
      return response instanceof Error 
        ? throwError(() => response) 
        : of(response);
    };
  });
}

// 测试用例中调用示例
it('处理自定义成功响应', () => {
  mockHttpsCallable({ status: 200, data: { formId: '1001' } });
  const fixture = TestBed.createComponent(YourTargetComponent);
  const component = fixture.componentInstance;
  
  component.saveForm({ username: 'test' });
  // 后续验证逻辑...
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:53:19