测试Angular组件时出现NG02200错误,寻求解决方法
Angular DashboardComponent单元测试错误排查与修复
问题背景
我正在做一个用于学习的Angular示例项目,组件从sessionStorage读取数据并展示,需要为DashboardComponent编写单元测试用例。默认的测试用例执行失败,尝试在Spec文件中手动创建existingUser数组后问题仍未解决。
相关代码
组件TS文件
export class DashboardComponent implements OnInit { existingUsers: User[] = []; constructor( private userservice: UserserviceService, private routerService: Router ) {} ngOnInit(): void { this.existingUsers = JSON.parse( sessionStorage.getItem('usersData') || '{}' ); this.userservice.newUserSubject.subscribe((user: any[]) => { if (user.length >= 1) { this.existingUsers.push(user[user.length - 1]); } }); sessionStorage.setItem('usersData', JSON.stringify(this.existingUsers)); } }
组件HTML文件
<div class="container responsive-grid"> <mat-card *ngFor="let users of existingUsers; let index = index"> <mat-card-header> <mat-card-title>{{ users.name }}</mat-card-title> </mat-card-header> <mat-card-actions> <button (click)="editUser(index, users)">Edit User</button> <button (click)="deleteUser(index)">Delete User</button> </mat-card-actions> <br /> <mat-card-content> <br /> <div> <strong><label for="name">Name</label></strong> {{ users.username }}<br /> <strong><label for="username">Email</label></strong> {{ users.email }}<br /> <div> <strong> Address</strong> <div> <strong><label for="street">Street</label></strong> {{ users.address.street }}<br /> </div> <div> <strong><label for="suite">Suite</label></strong> {{ users.address.suite }}<br /> </div> <div> <strong><label for="city">City</label> {{ users.address.city }}</strong><br /> </div> <div> <strong><label for="zipcode">PinCode</label> </strong>{{ users.address.zipcode }}<br /> </div> </div> </div> </mat-card-content> </mat-card> </div>
初始测试Spec文件
it('should create', () => { expect(component).toBeTruthy(); });
错误信息
Error: NG02200: Cannot find a differ supporting object '[object Object]' of type 'object'.
NgFor only supports binding to Iterables, such as Arrays.
Did you mean to use the keyvalue pipe?
问题根源
组件初始化时,当sessionStorage中不存在usersData时,用'{}'作为默认解析值,JSON.parse后得到空对象,但existingUsers声明为数组类型。*ngFor指令只能遍历数组这类可迭代对象,因此抛出NG02200错误。即使在测试中手动设置existingUser数组,组件的ngOnInit方法也会覆盖这个值,导致问题持续存在。
解决方案
1. 修复组件核心逻辑
将默认解析值从'{}'改为'[]',确保无论sessionStorage是否有数据,existingUsers始终是数组类型:
export class DashboardComponent implements OnInit { existingUsers: User[] = []; constructor( private userservice: UserserviceService, private routerService: Router ) {} ngOnInit(): void { // 改为空数组作为默认值,避免解析出对象 this.existingUsers = JSON.parse( sessionStorage.getItem('usersData') || '[]' ); this.userservice.newUserSubject.subscribe((user: any[]) => { if (user.length >= 1) { this.existingUsers.push(user[user.length - 1]); } }); sessionStorage.setItem('usersData', JSON.stringify(this.existingUsers)); } }
2. 编写正确的单元测试用例
模拟sessionStorage和用户服务的Subject,确保测试不依赖真实浏览器环境:
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DashboardComponent } from './dashboard.component'; import { UserserviceService } from '../userservice.service'; import { Router } from '@angular/router'; import { BehaviorSubject } from 'rxjs'; describe('DashboardComponent', () => { let component: DashboardComponent; let fixture: ComponentFixture<DashboardComponent>; let mockUserService: jasmine.SpyObj<UserserviceService>; let mockRouter: jasmine.SpyObj<Router>; let newUserSubject: BehaviorSubject<any[]>; beforeEach(async () => { // 创建模拟的Subject,用于测试订阅逻辑 newUserSubject = new BehaviorSubject<any[]>([]); // 模拟用户服务 mockUserService = jasmine.createSpyObj('UserserviceService', [], { newUserSubject: newUserSubject }); // 模拟路由服务 mockRouter = jasmine.createSpyObj('Router', ['navigate']); await TestBed.configureTestingModule({ declarations: [DashboardComponent], providers: [ { provide: UserserviceService, useValue: mockUserService }, { provide: Router, useValue: mockRouter } ] }).compileComponents(); // 模拟sessionStorage的读写方法 spyOn(sessionStorage, 'getItem').and.returnValue(JSON.stringify([])); spyOn(sessionStorage, 'setItem'); }); beforeEach(() => { fixture = TestBed.createComponent(DashboardComponent); component = fixture.componentInstance; fixture.detectChanges(); // 触发组件初始化 }); it('should create', () => { expect(component).toBeTruthy(); }); it('should initialize existingUsers from sessionStorage', () => { expect(sessionStorage.getItem).toHaveBeenCalledWith('usersData'); expect(component.existingUsers).toEqual([]); expect(sessionStorage.setItem).toHaveBeenCalledWith('usersData', JSON.stringify([])); }); it('should add new user when newUserSubject emits data', () => { const testUser = { name: 'Test User', username: 'test', email: 'test@example.com', address: { street: 'Test St', suite: '101', city: 'Test City', zipcode: '12345' } }; // 让Subject发射测试数据 newUserSubject.next([testUser]); // 验证用户被添加到数组中 expect(component.existingUsers.length).toBe(1); expect(component.existingUsers[0]).toEqual(testUser); }); });
内容的提问来源于stack exchange,提问作者sejal purohit
相关产品推荐
相关产品推荐

