合理的分页数据也够帮助我们快速的发现在组件中发生的逻辑性错误,本节我展示如何在MockApi中返回一个合格的分页数据。 ## 初始化 和后台的提供的教师分页接口相同,后台还提供了一个班级分页接口: ```bash GET /clazz/page ``` | **类型Type** | **名称Name** | **描述Description** | 必填 | **类型Schema** | 默认值 | | :------------ | :----------- | :----------------------- | ---- | :--------------------------- | --------- | | Param请求参数 | `page` | 第几页 | 否 | `number` | 0 | | Param请求参数 | `size` | 每页大小 | 否 | `number` | 20 | | Param请求参数 | sort | 排序字段及方式(支持多个) | 否 | `string`例:`sort=name,desc` | `id,desc` | | Response响应 | | Status Code: 200 | | `Page<Clazz>` | | 据此建立相应在clazz对应的MockApi文件夹,我们新建如下模拟返回数据: ```typescript +++ b/first-app/src/app/mock-api/clazz.mock.api.ts @@ -1,4 +1,7 @@ import {ApiInjector, MockApiInterface, randomNumber, RequestOptions} from '@yunzhi/ng-mock-api'; +import {Clazz} from '../entity/clazz'; +import {Teacher} from '../entity/teacher'; +import {Page} from '../entity/page'; /** * 班级模拟API @@ -30,6 +33,30 @@ export class ClazzMockApi implements MockApiInterface { } }; } + }, + { + method: 'GET', + url: '/clazz/page', + result: () => { + const size = 20; + const clazzes = new Array<Clazz>(); + for (let i = 0; i < size; i++) { + clazzes.push(new Clazz({ + id: i, + name: '班级', + teacher: new Teacher({ + id: i, + name: '教师' + }) + })); + } + return new Page<Clazz>({ + content: clazzes, + number: 2, + size, + numberOfElements: 20 + }); + } } ]; } ``` 如上述代码所示,模拟返回数据中的大多数代码与我们在上节组件中写的模拟代码相同。 ## 测试 MockApi完后后,我们在动态测试模块中加入相应的拦截器: ```typescript +++ b/first-app/src/app/clazz/clazz.component.spec.ts @@ -1,6 +1,9 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {ClazzComponent} from './clazz.component'; +import {MockApiTestingInterceptor} from '@yunzhi/ng-mock-api/testing'; +import {ClazzMockApi} from '../mock-api/clazz.mock.api'; +import {getTestScheduler} from 'jasmine-marbles'; describe('ClazzComponent', () => { let component: ClazzComponent; @@ -8,7 +11,10 @@ describe('ClazzComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ClazzComponent] + declarations: [ClazzComponent], + imports: [ + MockApiTestingInterceptor.forRoot([ClazzMockApi]) + ] }) .compileComponents(); }); ``` 然后手动控制数据返回,手动渲染组件: ```typescript fit('should create', () => { expect(component).toBeTruthy(); - fixture.autoDetectChanges(); + getTestScheduler().flush(); + fixture.detectChanges(); }); }); ``` 最后,删除C层中生成模拟数据的方法,转而调用`httpClient`从而完成班级分页的请求: ```typescript +++ b/first-app/src/app/clazz/clazz.component.ts @@ -2,6 +2,7 @@ import {Component, OnInit} from '@angular/core'; import {Page} from '../entity/page'; import {Clazz} from '../entity/clazz'; import {Teacher} from '../entity/teacher'; +import {HttpClient} from '@angular/common/http'; @Component({ selector: 'app-clazz', @@ -23,26 +24,11 @@ export class ClazzComponent implements OnInit { numberOfElements: 0 }); - constructor() { + constructor(private httpClient: HttpClient) { } ngOnInit(): void { - const clazzes = new Array<Clazz>(); - for (let i = 0; i < this.size; i++) { - clazzes.push(new Clazz({ - id: i, - name: '班级', - teacher: new Teacher({ - id: i, - name: '教师' - }) - })); - } - this.pageData = new Page<Clazz>({ - content: clazzes, - number: 2, - size: this.size, - numberOfElements: 20 - }); + this.httpClient.get<Page<Clazz>>('/clazz/page') 👈 + .subscribe(pageData => this.pageData = pageData); } } ``` 在这里使用了泛型来先后指定了当前`get`的元素类型为`Page`以及当前`Page`中的元素类型为`Clazz`,还需要注意的一点是虽然我们可以使用`/clazz/page`、`clazz/page`两种方式,但无论使用哪一种,都要保持组件中的调用与MockApi中的url相统一。 在组件的动态测试模块中加入MockApi拦截器并进行测试如下: ```typescript +++ b/first-app/src/app/clazz/clazz.component.spec.ts imports: [ HttpClientModule ], providers: [ { provide: HTTP_INTERCEPTORS, multi: true, useClass: MockApiTestingInterceptor.forRoot([ClazzMockApi]) } ] @@ -27,6 +27,7 @@ describe('ClazzComponent', () => { fit('should create', () => { expect(component).toBeTruthy(); - fixture.autoDetectChanges(); + getTestScheduler().flush(); + fixture.detectChanges(); }); }); ``` 最终效果如下: ![image-20210330160939270](https://img.kancloud.cn/ad/84/ad84131b0fd8224b1390119ccb88453d_2078x350.png) ## 完善API ### 随机数 在返回的班级名称、教师名称上加入一些随机数,会起到更好的模拟效果。同时这也有利于我们区分出不同的班级。 ```typescript +++ b/first-app/src/app/mock-api/clazz.mock.api.ts @@ -43,10 +43,10 @@ export class ClazzMockApi implements MockApiInterface { for (let i = 0; i < size; i++) { clazzes.push(new Clazz({ id: i, - name: '班级', + name: '班级' + Math.floor(Math.random() * 100).toString(10), teacher: new Teacher({ id: i, - name: '教师' + name: '教师' + Math.floor(Math.random() * 100).toString(10), }) })); } ``` `Math.random()`会生成一个0至1之间的随机值,该值与100相乘,会得到一个0-100内的随机值,`Math.floor()`方法去除其小数部分,最后得到一个0至100间的整数,在整数上调用`toString(10)`方法将其转换为字符串,期中`toString(10)`中的参数`10`表示转换为10进制。如此以来,MockApi便可以返回一些更容易区分的模拟数据了。 ![image-20210330161645874](https://img.kancloud.cn/0c/1e/0c1ed88f8d9784484813ebc18a615b64_1782x236.png) | 名称 | 链接 | | -------- | ------------------------------------------------------------ | | 本节源码 | [https://github.com/mengyunzhi/angular11-guild/archive/step6.3.3.zip](https://github.com/mengyunzhi/angular11-guild/archive/step6.3.3.zip) |