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

Angular 14中如何测试StoreService的HTTP删除API及模拟成功调用?

测试Angular 14中调用HTTP删除API的StoreService

一、模拟封装的HTTP删除API服务(返回Observable)的成功调用

假设我们有一个封装HTTP请求的ApiService,其中的删除方法返回Observable:

// api.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class ApiService {
  constructor(private http: HttpClient) {}

  deleteItem(id: number): Observable<{ success: boolean }> {
    return this.http.delete<{ success: boolean }>(`/api/items/${id}`);
  }
}

在测试中,我们可以通过Jasmine的createSpyObj创建ApiService的模拟对象,让其deleteItem方法返回一个包装了成功响应的Observable:

// store.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { StoreService } from './store.service';
import { ApiService } from './api.service';
import { of } from 'rxjs';

describe('StoreService', () => {
  let storeService: StoreService;
  let apiServiceSpy: jasmine.SpyObj<ApiService>;

  beforeEach(() => {
    // 创建ApiService的模拟实例,指定要mock的方法
    const spy = jasmine.createSpyObj('ApiService', ['deleteItem']);

    TestBed.configureTestingModule({
      providers: [
        StoreService,
        { provide: ApiService, useValue: spy }
      ]
    });

    storeService = TestBed.inject(StoreService);
    apiServiceSpy = TestBed.inject(ApiService) as jasmine.SpyObj<ApiService>;
  });

  // 测试成功调用删除API的场景
  it('should process successful deletion via ApiService', (done) => {
    const mockSuccessRes = { success: true };
    // 设置mock方法返回成功的Observable
    apiServiceSpy.deleteItem.and.returnValue(of(mockSuccessRes));

    storeService.deleteItem(1).subscribe({
      next: (res) => {
        expect(res).toEqual(mockSuccessRes);
        // 验证API方法被正确调用,参数符合预期
        expect(apiServiceSpy.deleteItem).toHaveBeenCalledWith(1);
        done();
      },
      error: () => {
        fail('删除请求应成功,不应进入错误分支');
        done();
      }
    });
  });
});

二、测试StoreService的完整删除逻辑

如果StoreService在调用API后有额外业务逻辑(比如更新本地数据),需要同时验证这些逻辑:

StoreService实现示例

// store.service.ts
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class StoreService {
  private localItems: { id: number; name: string }[] = [{ id: 1, name: '测试项' }];

  constructor(private apiService: ApiService) {}

  getLocalItems() {
    return [...this.localItems];
  }

  deleteItem(id: number): Observable<{ success: boolean }> {
    return this.apiService.deleteItem(id).pipe(
      tap(() => {
        // 删除本地数据
        this.localItems = this.localItems.filter(item => item.id !== id);
      })
    );
  }
}

对应的测试用例

// 验证本地数据是否被正确删除
it('should remove item from local storage after successful deletion', (done) => {
  apiServiceSpy.deleteItem.and.returnValue(of({ success: true }));

  // 初始状态校验
  expect(storeService.getLocalItems().length).toBe(1);

  storeService.deleteItem(1).subscribe({
    next: () => {
      expect(storeService.getLocalItems().length).toBe(0);
      done();
    },
    error: () => {
      fail('删除请求失败');
      done();
    }
  });
});

// 使用fakeAsync简化异步测试
it('should handle deletion with fakeAsync', fakeAsync(() => {
  const mockRes = { success: true };
  apiServiceSpy.deleteItem.and.returnValue(of(mockRes));

  let response: { success: boolean } | undefined;
  storeService.deleteItem(1).subscribe(res => response = res);

  tick(); // 触发Observable执行

  expect(response).toEqual(mockRes);
  expect(apiServiceSpy.deleteItem).toHaveBeenCalledWith(1);
  expect(storeService.getLocalItems().length).toBe(0);
}));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:22:45