在前面小節中我們使用`ng t`在單元測試的支撐下,完成了單一模塊下的單一組件開發。而組件最終仍然是要集成到整個系統中來運行的,所以組件完成后的集成測試也是必要的一環。
在項目根目錄下使用`ng s`來啟動項目,并打開 [http://localhost:4200/](http://localhost:4200/)來查看項目。
此時將在shell控制臺中得到如下錯語提示:
```bash
Error: app.component.html:15:22 - error TS2339: Property 'name' does not exist on type 'never'.
15 <td>{{ teacher.name }}</td>
~~~~
app.component.ts:6:16
6 templateUrl: './app.component.html',
~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component AppComponent.
...
```
>[success] 遇到錯誤的時候,第一件事情應該是翻譯錯誤提示、嘗試理解錯誤提示。
上述提示大體在說:由于在類型`never`并不存在`name`屬性,所以我們在V層上使用 `{{ teacher.name }}`是不被允許的。
這也說明了`ng serve`比`ng t`多了模板語法的檢查。
## 強類型
當前錯誤產生的根本原因是我們當前所使用TypeScript是個強類型語言,這要求每個變量都應該有類型,而且應該有正確的類型。
而我們在C層文件中,如下聲明了`teachers`的類型:
```bash
// 初始化教師數組
teachers = [];
```
即`teachers`的類型是個數組,而至于該數組中的第一項的類型是什么,我們并未說明。對應的V層文件:
```html
<tr *ngFor="let teacher of teachers; index as i"> ?
<td>{{ i + 1 }}</td>
<td>{{ teacher.name }}</td>?
```
* ? 執行ngFor的前提是teachers是個數組,而C層聲明正是數組,符合條件不報錯。
* ? 只有當數據中的數據中存在name時,才能夠獲取到name。而當前**未**聲明數組中的數據類型,typescript中如果未對數據類型進行聲明,則會默認其數據類型為`never`,表示:什么都不是。
解決此問題的方法即是為teachers中的數據項聲明類型,在此我們將其聲明為`any`類型,任**任意類型**,可以理解為:你想要的本類型都有。
>[info] never與any是個類型上的反義詞。never:本類型上什么都屬性都沒有,要什么沒什么;any:本類型上什么屬性都有,要什么有什么。
```typescript
// 初始化教師數組
teachers = [] as Array<any>;
```
或者:
```typescript
// 初始化教師數組
teachers = new Array<any>();
```
或者:
```typescript
// 初始化教師數組
teachers = [] as any[];
```
此時再次對`teachers`進行循環時,編譯器得知循環出的對象的類型是any,該類型上什么屬性都有,當然也必然有name屬性而不報錯了。
## 控制臺
在教程中提到控制臺基本上分為兩種:shell控制臺以及chrome控制臺,在開發過程中時刻關注控制臺是個要保持的好習慣。
雖然在shell控制臺已然看不到任何報錯信息,但[http://localhost:4200/](http://localhost:4200/)中卻查看不到任何內容,此時便應該去chrome控制臺中查看到底發生了什么。

報錯信息似曾相識,沒錯這就是那個由于未成功完成依賴注入時Angular給我們反饋的錯誤。但是我們明明已經在前面的開發中解決了這個問題,此時為何又出現了呢?
這時候便不得不重提下Angular的單元測試與模塊化設計了。
## ng t與ng s
與大多數的應用相同,運行環境(ng s)是看不到測試環境(ng t)的。這里的環境當前即指為了運行App組件而做的準備工作。
所以無論我們在測試環境中設置什么樣的內容,運行環境都無從感知。這當然包含我們在測試環境中為App組件引入的那個可提供`HttpClient`的`HttpClientModule`。
在`ng t`啟動的測試環境中,由`app.component.spec.ts`聲明了`DynamicTestModule`,該動態測試模塊提供了運行App組件的基本能力:
```bash
├── app-routing.module.ts
├── app.component.css ??
├── app.component.html ??
├── app.component.spec.ts ??
├── app.component.ts ??
└── app.module.ts
```
* `ng t`時,上述4個文件被關聯到DynamicTestModule中
而在`ng s`啟動的運行環境中,由`app.module.ts`聲明了`AppModule`模塊,該App模塊提供了運行App組件的基本能力:
```bash
├── app-routing.module.ts
├── app.component.css ??
├── app.component.html ??
├── app.component.spec.ts
├── app.component.ts ??
└── app.module.ts ??
```
* `ng s`時,上述4個文件被關聯到AppModule中
```typescript
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
```
如上述代碼所示`AppModule`并沒有引入那個可提供`HttpClient`的`HttpClientModule`。
問題的根本原因弄明白后,解決該問題也就簡單了:
```typescript
import {HttpClientModule} from '@angular/common/http'; ?
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule ?
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
```

>[success] spec.ts文件僅在`ng t`下生效,僅用于單元測試模式,運行環境將完全無視該類型文件。
- 序言
- 第一章 Hello World
- 1.1 環境安裝
- 1.2 Hello Angular
- 1.3 Hello World!
- 第二章 教師管理
- 2.1 教師列表
- 2.1.1 初始化原型
- 2.1.2 組件生命周期之初始化
- 2.1.3 ngFor
- 2.1.4 ngIf、ngTemplate
- 2.1.5 引用 Bootstrap
- 2.2 請求后臺數據
- 2.2.1 HttpClient
- 2.2.2 請求數據
- 2.2.3 模塊與依賴注入
- 2.2.4 異步與回調函數
- 2.2.5 集成測試
- 2.2.6 本章小節
- 2.3 新增教師
- 2.3.1 組件初始化
- 2.3.2 [(ngModel)]
- 2.3.3 對接后臺
- 2.3.4 路由
- 2.4 編輯教師
- 2.4.1 組件初始化
- 2.4.2 獲取路由參數
- 2.4.3 插值與模板表達式
- 2.4.4 初識泛型
- 2.4.5 更新教師
- 2.4.6 測試中的路由
- 2.5 刪除教師
- 2.6 收尾工作
- 2.6.1 RouterLink
- 2.6.2 fontawesome圖標庫
- 2.6.3 firefox
- 2.7 總結
- 第三章 用戶登錄
- 3.1 初識單元測試
- 3.2 http概述
- 3.3 Basic access authentication
- 3.4 著陸組件
- 3.5 @Output
- 3.6 TypeScript 類
- 3.7 瀏覽器緩存
- 3.8 總結
- 第四章 個人中心
- 4.1 原型
- 4.2 管道
- 4.3 對接后臺
- 4.4 x-auth-token認證
- 4.5 攔截器
- 4.6 小結
- 第五章 系統菜單
- 5.1 延遲及測試
- 5.2 手動創建組件
- 5.3 隱藏測試信息
- 5.4 規劃路由
- 5.5 定義菜單
- 5.6 注銷
- 5.7 小結
- 第六章 班級管理
- 6.1 新增班級
- 6.1.1 組件初始化
- 6.1.2 MockApi 新建班級
- 6.1.3 ApiInterceptor
- 6.1.4 數據驗證
- 6.1.5 教師選擇列表
- 6.1.6 MockApi 教師列表
- 6.1.7 代碼重構
- 6.1.8 小結
- 6.2 教師列表組件
- 6.2.1 初始化
- 6.2.2 響應式表單
- 6.2.3 getTestScheduler()
- 6.2.4 應用組件
- 6.2.5 小結
- 6.3 班級列表
- 6.3.1 原型設計
- 6.3.2 初始化分頁
- 6.3.3 MockApi
- 6.3.4 靜態分頁
- 6.3.5 動態分頁
- 6.3.6 @Input()
- 6.4 編輯班級
- 6.4.1 測試模塊
- 6.4.2 響應式表單驗證
- 6.4.3 @Input()
- 6.4.4 FormGroup
- 6.4.5 自定義FormControl
- 6.4.6 代碼重構
- 6.4.7 小結
- 6.5 刪除班級
- 6.6 集成測試
- 6.6.1 惰性加載
- 6.6.2 API攔截器
- 6.6.3 路由與跳轉
- 6.6.4 ngStyle
- 6.7 初識Service
- 6.7.1 catchError
- 6.7.2 單例服務
- 6.7.3 單元測試
- 6.8 小結
- 第七章 學生管理
- 7.1 班級列表組件
- 7.2 新增學生
- 7.2.1 exports
- 7.2.2 自定義驗證器
- 7.2.3 異步驗證器
- 7.2.4 再識DI
- 7.2.5 屬性型指令
- 7.2.6 完成功能
- 7.2.7 小結
- 7.3 單元測試進階
- 7.4 學生列表
- 7.4.1 JSON對象與對象
- 7.4.2 單元測試
- 7.4.3 分頁模塊
- 7.4.4 子組件測試
- 7.4.5 重構分頁
- 7.5 刪除學生
- 7.5.1 第三方dialog
- 7.5.2 批量刪除
- 7.5.3 面向對象
- 7.6 集成測試
- 7.7 編輯學生
- 7.7.1 初始化
- 7.7.2 自定義provider
- 7.7.3 更新學生
- 7.7.4 集成測試
- 7.7.5 可訂閱的路由參數
- 7.7.6 小結
- 7.8 總結
- 第八章 其它
- 8.1 打包構建
- 8.2 發布部署
- 第九章 總結