iT邦幫忙

2022 iThome 鐵人賽

DAY 8
1
Modern Web

今天我想來在 Angular 應用程式上加上測試保護系列 第 8

Day 8 - 單元測試 - 測試 Angular 元件 - 頁面顯示驗證

  • 分享至 

  • xImage
  •  

前言

先前已經針對 Angular 的管道 (Pipe) 與服務 (Server) 撰寫單元測試程式,接下來會陸陸續續說明如何撰寫 Angular 元件 (Component) 各種情境的測試程式。Angular 元件 (Component) 與服務 (Service) 不同地方在於:元件包含的頁面範本,以供使用者操作的頁面,而今天會先說明頁面顯示的正確性要如何透過單元測試程式進行驗證。

範例程式

這一篇會利用首頁元件 AppComponent (檔名為 app.component.ts) 進行說明。

<mat-toolbar color="primary">
  <span class="title">2022 鐵人賽範例</span>
  <button mat-raised-button color="primary" [routerLink]="['product', 'list']">
    產品清單
  </button>
  <span class="spacer"></span>
  <button mat-icon-button [routerLink]="['shopping-cart', 'list']">
    <mat-icon>shopping_cart</mat-icon>
  </button>
  <button mat-icon-button [routerLink]="['login']">
    <mat-icon>login</mat-icon>
  </button>
</mat-toolbar>
<div>
  <router-outlet></router-outlet>
</div>

測試模組的設定

如上面程式,在 AppComponent 元件中,使用了多個 Angular Material 的元件,因此如同於 AppMoulde 的設定一樣,需要在測試模組中引用對應的 Angular Material 元件模組;並將此元件加入測試模組的 declarations 陣列屬性中。

describe('AppComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        RouterTestingModule,
        MatButtonModule,
        MatToolbarModule,
        MatIconModule,
      ],
      declarations: [AppComponent],
    }).compileComponents();
  });
});

如一開始所說的,Angular 元件 (Component) 不同於服務 (Service) 的是多了使用者操作頁面,為此 Angular 提供了 ComponentFixture 來讓我們可以針對元件的頁面範本與邏輯程式進行測試。

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({ ... }).compileComponents();

    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
});

因此,如上面程式,在定義完 TestBed 之後,就會利用 TestBed 的 createComponent 方法來取得指定元件的ComponentFixture 物件,此物件內的 componentInstance 屬性記錄著 AppComponent 元件實體。需要注意的是,在呼叫此方法之後,TestBed 的組態定義就無法被更動。

最後,就可以利用從 fixture.componentInstance 屬性取得的元件實體,來判斷此元件是否在 Angular 應用程式執行時可以被建立,這也是在利用 Angular CLI 建立元件時,預設會新增的第一個測試案例。

it('元件應可以被建立', () => expect(component).toBeTruthy());

頁面元件實體的取得

ComponentFixutre 物件也提供了 debugElement 屬性,讓我們可以取得運行過程中,頁面 DOM 元素的樣式與屬性。因此我們就可以利用這個屬性,來檢驗頁面顯示的資訊是否正確。

it('標題應顯示為"2022 鐵人賽範例"', () => {
  // Arrange
  fixture.debugElement.query(By.css('.title'));

  // Act

  // Assert
});

我們可以利用 debugElement 屬性提供的 query 方法來搜尋頁面的 DOM 元素。我們可以如同上面程式,使用 By.css(‘.title’) 語句來取得頁面上包含 .title 樣式類別的 DOM 元素;By.css() 方法指定的是一 CSS 選擇器字串,所以除了 css 類別外,也可以指定標籤名稱或 ID 名稱。

除了利用樣式搜尋頁面 DOM 元素外,也可以利用 By.directive() 方法來取得指定特定元件類型的頁面元素。例如,當我們希望取得頁面上 MatButton 按鈕元件時,就可以寫成:

const button = fixture.debugElement.query(By.directive(MatButton));

不過,在 AppComponent 元件中有三個 MatButton 按鈕元件,利用上面程式只會取得第一個元件,若要取得所有的按鈕元件,則會使用 debugElementqueryAll() 方法。

const buttons = fixture.debugElement.queryAll(By.directive(MatButton));

頁面顯示的驗證

在利用 query() 方法取得標題元素後,就可以利用 DebugElement 內的 nativeElement 取得原生的 DOM 元素,進而去驗證此 DOM 元素屬性值內容。

it('標題應顯示為"2022 鐵人賽範例"', () => {
  // Arrange
  const titleElement = fixture.debugElement.query(By.css('.title')).nativeElement;

  // Act

  // Assert
  expect(titleElement.textContent).toBe('2022 鐵人賽範例');
});

執行測試程式

如先前文章一樣,最後利用 ng test 命令來確認測試結果。

https://ithelp.ithome.com.tw/upload/images/20220923/20109645VrCxRVaCCW.png

接下來

這一篇先透過固定的標題文字來說明如何測試 Angular 元件頁面顯示結果,完整的測試程式放在 GitHub 中。不過,實務上更常實作的是:依照使用的資料顯示頁面內容;接下來就會針對此種測試案例進行說明。


上一篇
Day 7 - 單元測試 - 測試使用 HttpClient 的 Angular 服務
下一篇
Day 9 - 單元測試 - 測試 Angular 元件 - 資料繫結測試
系列文
今天我想來在 Angular 應用程式上加上測試保護30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言