如何在Angular v19+Signals中编写TanStack Angular Query的测试用例
Angular v19 + TanStack Query (Signals) 测试方案指引
测试环境准备
- 确保项目已安装
@tanstack/angular-query-experimental(对应Angular Signals版本)及@tanstack/query-core - 测试模块中通过
provideAngularQuery配置测试专用QueryClient,关闭重试、缓存时间等干扰测试的默认配置
基础组件测试示例
假设你有如下使用 injectQuery 的组件:
@Component({ selector: 'app-user-view', template: ` <div *ngIf="data().isLoading">Loading...</div> <div *ngIf="data().error">{{ data().error.message }}</div> <div *ngIf="data().data">{{ data().data.name }}</div> `, standalone: true, }) export class UserViewComponent { private api = inject(UserApiService); data = injectQuery(() => ({ queryKey: ['user'], queryFn: () => this.api.getCurrentUser(), })); }
对应的测试用例:
import { TestBed } from '@angular/core/testing'; import { UserViewComponent } from './user-view.component'; import { UserApiService } from './user-api.service'; import { provideAngularQuery } from '@tanstack/angular-query-experimental'; import { QueryClient } from '@tanstack/query-core'; describe('UserViewComponent', () => { let apiSpy: jasmine.SpyObj<UserApiService>; let queryClient: QueryClient; beforeEach(async () => { apiSpy = jasmine.createSpyObj('UserApiService', ['getCurrentUser']); // 初始化测试用QueryClient queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: 0 }, }, }); await TestBed.configureTestingModule({ imports: [UserViewComponent], providers: [ provideAngularQuery(() => ({ queryClient })), { provide: UserApiService, useValue: apiSpy }, ], }).compileComponents(); }); it('should render loading state initially', () => { const fixture = TestBed.createComponent(UserViewComponent); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Loading...'); }); it('should render user data on query success', async () => { const mockUser = { name: 'Alice' }; apiSpy.getCurrentUser.and.returnValue(Promise.resolve(mockUser)); const fixture = TestBed.createComponent(UserViewComponent); fixture.detectChanges(); // 等待Query完成并更新Signal await queryClient.refetchQueries({ queryKey: ['user'] }); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Alice'); expect(apiSpy.getCurrentUser).toHaveBeenCalledTimes(1); }); it('should render error message on query failure', async () => { apiSpy.getCurrentUser.and.returnValue(Promise.reject(new Error('Failed to fetch user'))); const fixture = TestBed.createComponent(UserViewComponent); fixture.detectChanges(); await queryClient.refetchQueries({ queryKey: ['user'] }); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Failed to fetch user'); }); });
缓存与Signal更新测试
直接操作QueryClient缓存验证Signal响应性:
it('should update view when cache data changes', () => { // 预设置缓存数据 queryClient.setQueryData(['user'], { name: 'Bob' }); const fixture = TestBed.createComponent(UserViewComponent); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Bob'); // 更新缓存,Signal自动同步 queryClient.setQueryData(['user'], { name: 'Charlie' }); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Charlie'); });
常见问题处理
- Signal未触发视图更新:异步操作后必须调用
fixture.detectChanges(),或用await fixture.whenStable()等待所有异步任务完成 - Query未自动执行:检查QueryClient配置,确保未设置
enabled: false,或手动调用queryClient.fetchQuery({ queryKey: ['user'], queryFn: ... })触发请求 - 依赖注入报错:确保测试模块中通过
provideAngularQuery正确传入测试用QueryClient,而非使用生产环境配置
内容的提问来源于stack exchange,提问作者Eternal Sunshine
相关产品推荐
相关产品推荐

