在前面教师管理的功能开发中,我们已经有了获取教师管理的接口,该规范为: `GET /Teacher/` 当查询数据成功后返回教师列表信息,在此我们直接使用该接口。 ## 先写断言 按照TDD测试驱动开发的理论,在进行某个功能开发以前首先需要清晰明了的知道自己想要的内容是什么,而想要的内容是什么则可以通过写测试代码来描述出来。所以测试代码应该在功能代码以前。但在实际的开发中,TDD的开发对我们的功底要求比较高,在此我们尝试使用这种理论进行本小节动态获取后台教师列表数据的功能开发。 klass/teacher-select/teacher-select.component.spec ``` /*断言发请了后台请求,模拟返回数据后,断言V层的select个数为2*/ fit('获取教师列表后选择教师', () => { expect(component).toBeTruthy(); const httpTestingController: HttpTestingController = TestBed.get(HttpTestingController); const req = httpTestingController.expectOne('http://localhost:8080/Teacher'); expect(req.request.method).toEqual('GET'); const teachers = new Array(new Teacher(1, 'panjie', '潘杰'), new Teacher(2, 'zhangxishuo', '张喜硕')); req.flush(teachers); fixture.detectChanges(); ① const htmlSelectElement: HTMLSelectElement➊ = fixture.debugElement.query(By.css('#teacherSelect')).nativeElement; expect(htmlSelectElement.length).toBe(2); ➋ }); ``` * ① 很重要,获取HTML元素前,必须重新渲染V层。 * ➊ 声明该HTML元素的类型(很有必要,这将减少在后续代码中书写的错误率)。 * ➋ 断言select中有两个option ## 再写功能代码 有了断言后,我们再根据断言的提示信息来写功能代码。这像极了软件开发的过程:1. 甲方提需求 2. 我们按需求开发功能 3. 功能与需求相吻合开发完成。 ``` Chrome 78.0.3904 (Mac OS X 10.13.6) TeacherSelectComponent 获取教师列表后选择教师 FAILED Error: Expected one matching request for criteria "Match URL: http://localhost:8080/Teacher", found none. ``` 报错说,我们期望组件发起一个`http://localhost:8080/Teacher`的请求,但是一个也没有找到。我们补充C层代码: ``` constructor(private httpClient: HttpClient) { } /** * 获取所有的教师,并传给V层 */ ngOnInit() { this.teacherSelect = new FormControl(); const url = 'http://localhost:8080/Teacher'; this.httpClient.get(url) .subscribe((teachers: Array<Teacher>) => { this.teachers = teachers; }); } ``` ### 完善测试 最后对option中的值进行测试,看是否正确的将教师姓名进行展示: ``` const teachers = new Array(new Teacher(1, 'panjie', '潘杰'), new Teacher(2, 'zhangxishuo', '张喜硕')); ① ... /*断言发请了后台请求,模拟返回数据后,断言V层的select个数为2*/ fit('获取教师列表后选择教师', () => { expect(component).toBeTruthy(); const httpTestingController: HttpTestingController = TestBed.get(HttpTestingController); const req = httpTestingController.expectOne('http://localhost:8080/Teacher'); expect(req.request.method).toEqual('GET'); req.flush(teachers); fixture.detectChanges(); const htmlSelectElement: HTMLSelectElement = fixture.debugElement.query(By.css('#teacherSelect')).nativeElement; expect(htmlSelectElement.length).toBe(2); testOptionValue(htmlSelectElement); ② }); /** * 断言option的值与teacher中name的相同 * 循环teachers数组。断言与option的值一一相等 * @param htmlSelectElement html元素 */ const testOptionValue = (htmlSelectElement: HTMLSelectElement) => { ② const htmlOptionElements: HTMLCollectionOf<HTMLOptionElement>➊ = htmlSelectElement.options; for (let i = 0; i < teachers.length; i++) { const htmlOptionElement: HTMLOptionElement = htmlOptionElements.item(i); console.log(htmlOptionElement.text); expect(htmlOptionElement.text).toEqual(teachers[i].name); } }; ``` * ① 抽离公共的变量 * ② 定义子函数并调用 * ➊ 返回值的类型请参阅本小节最小方的官方文档 #### 测试 ``` LOG: '潘杰' Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 0 of 12 SUCCESS (0 secs / 0 secs) LOG: '张喜硕' Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 0 of 12 SUCCESS (0 secs / 0 secs) Chrome 78.0.3904 (Mac OS X 10.13.6): Executed 1 of 12 (skipped 11) SUCCESS (0.115 secs / 0.095 secs) TOTAL: 1 SUCCESS TOTAL: 1 SUCCESS ``` # 参考文档 | 名称 | 链接 | 预计学习时长(分) | | --- | --- | --- | | 源码地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.5.2](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.5.2) | - | | HTMLSelectElement | [https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement) | 5 | | HTMLSelectElement.options | [https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/options](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/options) | 5 |