iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
Modern Web

Angular TDD (Test-driven development ) 從0到1系列 第 19

Angular TDD 測試從0到1: Day 19 Typescript Unit Test(5) - Detector Change

  • 分享至 

  • xImage
  •  

終於來到 TS 最後一篇測試範例了,今天要來認識 detector change 的測試方法

課程名稱如下:

  • Testing The Change Detector
  • Testing Functions In The Constructor
  • Testing The Change Detector In The Constructor

元件的 function 變數

我們先來看看,原始元件 typescript 檔案

  1. Change Detector 元件,changeDetecor,是當元件上的值有變化時會自動更新 UI,我們可以將 change detector 抽出來讓 UI 不再自動更新,或者透過手動呼叫 detect change function 更新元件。可是,change detector 和其他一般 service 不同,沒辦法 inject 到 testbed做測試,但是元件本身呼叫 detectChange 來測試。

  2. Functions In The Constructor 元件,constructor 是在元件建立後第一個執行的地方,所以沒辦法手動呼叫 constructor 中的 service,為了解決這個問題,我們需要建立新的元件,在透過新元件呼叫 constructor 的服務。

  3. Change Detector In The Constructor 元件,這個測試案例是結合 detector change 和 contrustor 的方式進行,因為無法在元件建立後測試 constructor,所以需要用新元件呼叫,細節留到後面 spec 說明。

如何測試 function

來看看,對應的 Spec 檔案,configureTestingModule 一樣取代成測試用的元件

  1. Change Detector 元件
  beforeEach(waitForAsync(() => {
      configureTestingModule({
          declarations: [
            TestingTheChangeDetectorComponent
          ],
      }).compileComponents();
  }));

changeDetecor 是 private 參數,所以用 key 的方式取得 line 5,透過 spyOn 取得 detectorChanges function,然後透過呼叫元件的 ngOnInit 測試變更。

  it('should update the UI after loading the data', () => {
    //Assign
    // const changeDetector = TestBed.inject(ChangeDetectorRef); // Won't work
    
    const changeDetector = component['changeDetector'];
    const detectChangesSpy = spyOn(changeDetector, 'detectChanges');

    // This also works, but avoid using prototype if you don't need to
    // const changeDetector = componentFixture.debugElement.injector.get(ChangeDetectorRef);
    // const detectChangesSpy = spyOn(changeDetector.constructor.prototype, 'detectChanges');

    //Act
    component.ngOnInit();

    //Assert
    expect(detectChangesSpy).toHaveBeenCalledWith();
  });
  1. Functions In The Constructor 元件
  beforeEach(waitForAsync(() => {
      configureTestingModule({
          declarations: [
            TestingFunctionsInTheConstructorComponent
          ],
      }).compileComponents();
  }));

前面有提到,因為沒辦法用手動呼叫 constructor,需要透過「建立新元件」trigger contructor,由於在建立新元件前就spy ApiService,讓我們可以檢查 function getData

  it('should get the data from the api on construction', () => {
    //Assign
    const apiService = TestBed.inject(ApiService);
    spyOn(apiService,'getData');

    //Act
    TestBed.createComponent(TestingFunctionsInTheConstructorComponent);

    //Assert
    expect(apiService.getData).toHaveBeenCalledWith();
  });
  1. Change Detector In The Constructor 元件
  beforeEach(waitForAsync(() => {
      configureTestingModule({
          declarations: [
            TestingTheChangeDetectorInTheConstructorComponent
          ],
      }).compileComponents();
  }));

這邊是結合上述兩種測例,但是我們無法用建立新元件方式 trigger constructor,需要調用 prototype 的 instance 來使用

  it('should detach from the change detector on construction', () => {
    //Assign
    // const changeDetector = TestBed.inject(ChangeDetectorRef); // Won't work
    
    // This won't work either as we create a new component
    // const changeDetector = component['changeDetector'];
    // const detectChangesSpy = spyOn(changeDetector, 'detectChanges');

    // This won't work either
    // const detectChangesSpy = spyOn(ChangeDetectorRef.prototype, 'detach');

    const changeDetector = componentFixture.debugElement.injector.get(ChangeDetectorRef);
    const detectChangesSpy = spyOn(changeDetector.constructor.prototype, 'detach');

    //Act
    TestBed.createComponent(TestingTheChangeDetectorInTheConstructorComponent);

    //Assert
    expect(detectChangesSpy).toHaveBeenCalledWith();
  });

上一篇
Angular TDD 測試從0到1: Day 18 Typescript Unit Test(4) - Navigation, Local Storage
下一篇
Angular TDD 測試從0到1: Day 20 HTML Template Unit Test(1) - 取得元素的方法
系列文
Angular TDD (Test-driven development ) 從0到130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言