<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                本節將展示如何在沒有后臺的情況下模擬后臺數據,完成組件C層的開發。 # 定義接口 后臺此時雖然尚不存在,但接口規范則一定有了。比如在獲取教師列表時,團隊成員根據原型和團隊規范討論后定義了如下接口。 ``` GET /Klass ``` ##### 參數 Parameters | type | name | Description | Schema | | --- | --- | --- | --- | | **Query** | **name** <br> *requried* | 班級名稱 | string | ##### 響應(返回值)Responses | HTTP Code | Description | Schema | | --- | --- | --- | | **200** | OK | `Array<Teacher>`| 轉換為語言描述:使用`GET /Klass`來請求班級的所有數據,在請求中必須傳入`name`參數,該參數的類型為`String`;請求成功后,返回狀態碼為`200`,返回數據為班級數組。 # 數據請求 根據原型的功能需求,C層代碼如下: klass/index/index.component.ts ``` import {Component, OnInit} from '@angular/core'; import {Klass} from '../../norm/entity/Klass'; import {Teacher} from '../../norm/entity/Teacher'; import {HttpClient} from '@angular/common/http'; @Component({ selector: 'app-index', templateUrl: './index.component.html', styleUrls: ['./index.component.sass'] }) export class IndexComponent implements OnInit { private message = ''; private url = 'http://localhost:8080/Klass'; /*查詢參數*/ params = { name: '' }; /* 班級 */ klasses; constructor(private httpClient: HttpClient) { } ngOnInit() { this.onQuery(); } /** * 附帶參數發起數據查詢 */ onQuery(): void { this.httpClient.get(this.url, {params: this.params}?) .subscribe(data => { this.klasses = data; }, () => { console.log(`請求${this.url}發生錯誤`); }); } } ``` * ? 查詢條件放到`HttpClient.get`接收的第二個參數的`params`屬性中。 > `HttpClient.get(string)`與`HttpClient.get(string, {})`都是發起`get`請求的正確寫法。當發起`get`請求時需要附加其它信息的時候,我們使用`HttpClient.get(string, {})`,并在第二個參數`{}`將特定的信息寫入。 ## 測試 `ng test`進行測試,得到以后錯誤信息: ``` NullInjectorError: StaticInjectorError(DynamicTestModule)\[IndexComponent -> HttpClient\]: StaticInjectorError(Platform: core)\[IndexComponent -> HttpClient\]: NullInjectorError: No provider for HttpClient! ``` 上面是說發生了`空注入器`異常,具體的原因是在構建`IndexComponent`時`沒有找到HttpClient`的提供者。基于以下理論: * 依賴注入:在構造函數中聲明所需要的對象類型,`angular`會自動給我們一個對象。 * 依賴間的關系發生在`module`層面,我們如果想使用`HttpClient`,那么必須在`module`中聲明我們需要`HttpClientModule`。 我們發現問題的原因在于:進行測試時,沒有在`module`層面聲明需要`HttpClientModule`來幫忙。我們又知道`klassIndex`組件屬于`klass`模塊,所以嘗試向klass.module.ts中添加`import`。 ``` klass/klass.module.ts import {NgModule} from '@angular/core'; import {IndexComponent} from './index/index.component'; import {HttpClientModule} from '@angular/common/http'; ? /** * 班級模塊 */ @NgModule({ declarations: [IndexComponent], imports: [HttpClientModule] ? }) export class KlassModule { } ``` 再試測試,發現錯誤仍然存在。 > 當發現歷史的理論不足以支撐當前的現象時,恭喜你,你的理論知識馬上會隨著解決當前問題而提升。而且此理論一旦提升就很難忘卻,是真真切切的學習到心里了。 這個原因是這樣:此時的單元測試是對象是`組件`這個獨立體,在進行測試時單元測試并沒有將它集成到某個`模塊`中,所以即使我們在`klass模塊`中添加了相關的依賴,由于單元測試根本就沒有獲取`模塊`中的信息,當然也就不會生效了。 # 初探單元測試 在單元測試時,單元測試會臨時生成了一個測試`Module`,然后再將待測試的`Component`變到此測試`Module`中。所以在測試過程中,被測試組件所依賴的`Moudle`為測試`Module`。 klass/index/index.component.spec.ts ``` beforeEach(async(() => { ? TestBed.configureTestingModule({ ? declarations: [IndexComponent] ? }) .compileComponents(); ? })); beforeEach(() => { ? fixture = TestBed.createComponent(IndexComponent); ? component = fixture.componentInstance; ? fixture.detectChanges(); ? }); it('should create', () => { ? expect(component).toBeTruthy(); ? }); ``` * ? 每次執行本文件的測試用例前,都執行一次此方法中的內容。 * ? 為測試平臺配置測試模塊。 * ? 將待測組件添加到測試平臺中。 * ? 編譯組件。 * ? 創建包含IndexComponent的容器(固定裝置)。 * ? 獲取該容器(固定裝置)的組件。 * ? 查看組件是否發生了變化,如發生變化則重新渲染組件。 * ? 聲明測試用例。 * ? 預測組件被成功的創建了出來。 通過上述代碼的分析,我們大體能夠得到以下信息: ![](https://img.kancloud.cn/c8/c9/c8c9b2919bc132abb788a7e703ca6984_351x239.png) 總結如下: * [ ] `TestBed`是個可以配置測試模塊的`測試平臺`,對測試模塊進行配置后通過`compile 編譯`來預生成`component 組件`(這有點類似于C語言,先編譯再運行)。 * [ ] 每個組件都有一個包含自己的容器,該容器可以監測組件是否發生變化。 * [ ] 容器是由測試平臺創建出來的,而組件是由容器創建出來的。 # 配置單元測試 由于剛剛的理論,解決剛剛的問題就不再困難了,既然需要在測試平臺上進行測試模塊的配置,那我們將`HttpClientModule`引入到測試模塊即可: klass/index/index.component.spec.ts ``` beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [IndexComponent], imports: [HttpClientModule] ? }) .compileComponents(); })); ``` 保存后單元測試正常通過,也恰好的驗證了我們前面的猜想。 # 模似HTTP請求 `HttpClientModule`中的`HttpClient`是用于正常的數據請求的,如果我們此時后臺相應的接口存在是可以完成正常的請求的。但如果前臺的開發早于后臺,在無后臺支持的情況下`HttpClientModule`中的`HttpClient`向預定的接口發起請求,則會在控制臺中得到以下網絡請求錯誤。 ![](https://img.kancloud.cn/6b/90/6b9042f757bbbc544e11ed1446c67013_1276x634.png) 此時,我們急切的需要一個能夠由我們自定義返回結果的、供我們在開發時使用的`HttpClient`。強大的angular為我們準備了`HttpClientTestingModule`,`HttpClientTestingModule`中的`HttpClient`擁有著與`HttpClientModule`中的`HttpClient`相同的外表,但也同時擁有完美支持測試的不一樣的內涵。 與`HttpClientModule`相同,`HttpClientTestingModule`同樣也擁有一個`HttpClient`,這兩個`HttpClient`在使用方法上完全相同,唯一的不同便是前面的進行數據請求時發起的是真實的請求,而后一個發起的則是模擬的請求。我們不旦可以定義返回的數據的內容,還可以定義返回數據的時間。 klass/index/index.component.spec.ts ``` import {HttpClientTestingModule} from '@angular/common/http/testing'; ① beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [IndexComponent], imports: [HttpClientTestingModule] ? }) .compileComponents(); })); ``` * ? 使用`HttpClientTestingModule`替換`HttpClientModule` 此時我們觀察控制臺,數據請求的報錯信息已經不再出現。為了進一步的弄清楚整個的流程,我們在`klass/index/index.component.ts`的`onQuery`方法中加入以下測試代碼: ``` /** * 用戶點擊查詢按鈕后觸發 */ onQuery(): void { console.log('執行onQuery'); ? this.httpClient.get(this.url, {params: this.params}) .subscribe(data => { console.log('成功執行請求', data); ? this.klasses = data; }, () => { console.log(`請求${this.url}發生錯誤`); ? }); } ``` 測試: ![](https://img.kancloud.cn/a3/4b/a34ba4fa4f784f9fbbf9682022f6c992_310x123.png) 測試說明`onQuery`方法被正確的執行了;也成功的對可觀察的`this.httpClient.get(this.url, {params: this.params})`進行了`subscribe 訂閱`,但該觀察者無論是成功的數據還是失敗的數據,都沒有發送給我們。這是因為前面我們剛剛描述過的:`HttpClientTestingModule`中的`HttpClient`何時發送數據,發送什么樣的數據都是由我們在測試中決定的。 ## 返回數據 在測試中我們如此的返回測試數據。 klass/index/index.component.spec.ts ``` import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {IndexComponent} from './index.component'; import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; ① import {Klass} from '../../norm/entity/Klass'; ① import {Teacher} from '../../norm/entity/Teacher'; ① fdescribe('IndexComponent', () => { let component: IndexComponent; let fixture: ComponentFixture<IndexComponent>; let httpTestingController: HttpTestingController; ② beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [IndexComponent], imports: [HttpClientTestingModule] }) .compileComponents(); })); beforeEach(() => { httpTestingController = TestBed.get(HttpTestingController); ? fixture = TestBed.createComponent(IndexComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); const req = httpTestingController.expectOne('http://localhost:8080/Klass?name='); ? const klasses = [ ? new Klass(1, '計科1901班', new Teacher(1, 'zhagnsan', '張三')), new Klass(2, '軟件1902班', new Teacher(2, 'lisi', '李四')) ]; req.flush(klasses); ? fixture.detectChanges(); ? }); }); ``` * ? 獲取`HttpTestingController Http測試控制器` * ? 預測已經向`http://localhost:8080/Klass?name=`發起了請求。 * ? 定義返回值。 * ? 使用klasses數據回應`http://localhost:8080/Klass?name=`請求。 * ? 查看組件是否發生了變化,如發生變化則重新渲染組件。 **請思考:** 為什么是`http://localhost:8080/Klass?name=`而不是`http://localhost:8080/Klass`呢? ### 測試 ![](https://img.kancloud.cn/2f/6f/2f6f24f22e980355109a53bc5c974b81_388x243.png) # 參考文檔 | 名稱 | 鏈接 | 預計學習時長(分) | | --- | --- | --- | | 源碼地址 | [https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.2.5](https://github.com/mengyunzhi/spring-boot-and-angular-guild/releases/tag/step3.2.5) | - | | 測試Http請求 | [https://www.angular.cn/guide/http#testing-http-requests](https://www.angular.cn/guide/http#testing-http-requests) | 15 | | 單獨測試組件 | [https://www.angular.cn/guide/testing#component-class-testing](https://www.angular.cn/guide/testing#component-class-testing) | 15 | | detectchanges | [https://www.angular.cn/guide/testing#detectchanges](https://www.angular.cn/guide/testing#detectchanges) | | 10 |
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看