[英]How to test angular component
我有一個組件,它依賴於一個服務,它也有一些依賴關系。 (組件調用服務方法,並使用主題獲取可觀察的返回。)
零件:
export class CoursesComponent implements OnInit {
courses: Observable<Course[]>;
constructor(private courseService: CourseService) {
this.courseService.loadCourses();
}
ngOnInit(): void {
this.courses = this.courseService.course;
}
}
服務
@Injectable()
export class CourseService {
private courseSubject: Subject<Course[]> = new Subject();
course = this.courseSubject.asObservable();
constructor(private courseApiService: CourseApiService,
private router: Router,
private route: ActivatedRoute) { }
loadCourses(title?: string, end?: number): Subscription {
return this.getCourses(title, end).subscribe((courses: Course[]) => this.courseSubject.next(courses));
}
private getCourses(title?: string, end?: number): Observable<Course[]> {
return this.courseApiService.getCourses(title, end);
}
}
我嘗試測試組件並遇到麻煩:我不想向 TestBed 注入真正的服務,所以起初我試圖監視所有 courseService 方法:
const courseServiceMethods = [
'loadCourses',
'postCourse',
'editCourse',
'getCourseById',
'removeCourseById',
'navigateById'];
describe('CoursesComponent', () => {
let component: CoursesComponent;
let fixture: ComponentFixture<CoursesComponent>;
let courseService: SpyObj<CourseService>;
beforeEach(async(() => {
courseService = jasmine.createSpyObj('CourseService', courseServiceMethods);
TestBed.configureTestingModule({
declarations: [ CoursesComponent, SearchComponent ],
providers: [
{provide: CourseService, useValue: courseService},
]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CoursesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
describe('onDelete()', () => {
it('should call removeCourseById()', () => {
component.onDelete('2');
expect(courseService.removeCourseById).toHaveBeenCalled();
});
});
但是使用這種方法,我只能檢查是否調用了服務中的某些方法並且無法觀察到這給了我的數據。 所以我有另一個選擇:在 spec.ts 中為 course.service 編寫我自己的模擬 class 並在 TestBed 中提供:
@Injectable()
class Mock {
private courseSubject: Subject<Course[]> = new Subject();
course = this.courseSubject.asObservable();
loadCourses(title?: string, end?: number): Subscription {
return this.getCourses(title, end).subscribe((courses: Course[]) => this.courseSubject.next(courses));
}
private getCourses(title?: string, end?: number): Observable<Course[]> {
return of(coursesMockArray);
}
}
但是有了這個選項,我必須模擬 courseService 中的所有方法,如果它太大了? 是否有機會監視課程服務中的方法並檢查返回數據?
你可以做:
it('should call removeCourseById()', () => {
spyOn(courseService.removeCourseById).and.returnValue(of(true)); // or whatever you want to mock
component.onDelete('2');
expect(courseService.removeCourseById).toHaveBeenCalled();
});
我會在組件中而不是在服務中進行訂閱,盡管它們是有限的可觀察對象,但對我來說,它們在服務中被訂閱似乎很奇怪。
解決方案 1
您需要創建服務的固定裝置(如果默認情況下您可能有),如果沒有,您可以創建如下:
export class CourseServiceFixture implements Readonly<CourseService>{
public loadCourses= jest.fn();
//i am using jest you might be using jasmine you may have to write jasmine mock fun
}
然后在組件的 spec.ts 文件中創建一個變量:
let mockCourseService: CourseServiceFixture;
現在您需要將變量分配為 object 並在 providers[] 數組中使用它:
beforeEach(async(() => {
//this is must
mockCourseService = new CourseServiceFixture();
courseService = jasmine.createSpyObj('CourseService', courseServiceMethods);
TestBed.configureTestingModule({
declarations: [ CoursesComponent, SearchComponent ],
providers: [
{provide: CourseService, useValue: mockCourseService},
]
})
.compileComponents();
}));
現在,每次您想使用該服務時,您都可以使其模擬夾具文件中定義的方法的返回值,例如:
it('should have some courses', () => {
mockCourseService.loadCourses.mockReturnValue(['a','b','c']);
fixture.detectChanges();
expect(component.courses).toBe([...]);
});
解決方案 2如果您不想創建夾具文件,它也在文檔中給出
let mockCourseService: Partial<CourseService>;
beforeEach(() => {
mockCourseService= {
courses: [...],
};
providers: [ { provide: CourseService, useValue: mockCourseService} ],
}
您還需要注入服務:
userService = TestBed.inject(UserService);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.