昨天我們說說了關於CI/CD之中的對於檢驗的需求與要求,今天我們來講講Unit Test吧
在Angular原本内嵌的的測試元件是使用karma+jasmine進行測試的,karma負責建構起瀏覽器測試環境,jasmine負責進行檢驗的實作
這樣子的運作得以讓我們在正式環境之中可以運行我們的函式,以及有個GUI介面來讓我們看到測試過程與結果
但最後Angular開發團隊在眾多社群的回饋之中,歸納整理了大家對於調整優化的需求,其中有一項就是建構一個實體的測試環境太過臃腫與肥大
想想看,當我們要在CI的pipe執行過程中,我們必須先起一個環境,起了環境之後才能進行測試
這樣子的架構流程對於CI的流程來說可以說是非常致命的
也因此Angular@16中,Angular開發團隊表示他們正在添加對於Jest的初步嘗試與支援。
Jest 最初由 Facebook 開發,並且已被廣泛用於測試 React 應用程序,但它同樣適用於測試其他 JavaScript 項目。他可以更加直接的進行外部引用Service與pipe的Mask與Spy,這點就非常幫助我們在CI的流程上進行檢核了
接下來我們來說說怎麼在Angular16安裝與實作Jest
首先,我們先把karma-serious與jasmine都先在packahe.json移除掉,然後再重新npm i一次
然後我們來安裝他吧
npm install --save-dev jest jest-preset-angular @types/jest
我們這樣子就完成了安裝,接下來則是調整參數,首先先宣告npm run 的指令
    "test": "jest --verbose",
    "test:coverage": "jest --coverage",
    "test:watch": "jest --watch",
然後我們在我們的跟目錄建立一個jest.config.ts
import type { Config } from 'jest';
const config: Config = {
  preset: 'jest-preset-angular',
  setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
  globalSetup: 'jest-preset-angular/global-setup',
  moduleNameMapper: {
    '^src/(.*)$': '<rootDir>/src/$1',
  },
};
export default config;
並在tsconfig.spec.json之中在compilerOptions宣告type
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/spec",
    "types": [
      "jest" <--這裡
    ]
  },
  "include": [
    "src/**/*.spec.ts",
    "src/**/*.d.ts",
    "**/*.spec.ts"
  ]
}
最後的最後,我們一樣在root創建一個setup-jest.ts用它來宣告jest-preset-angular並將其實作在我們的專案之中
import 'jest-preset-angular/setup-jest';
window.open = jest.fn();
就這樣,我們完成了安裝,接下來我們來看看簡單的我們怎麼實作我們的環境建置
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [SalesAgreementComponent, ReactiveFormsModule, FormsModule],
      providers: [
        provideHttpClient(),
        provideHttpClientTesting(),
        provideMockStore({}),
        MessageService,
      ],
    }).compileComponents();
  });
我們可以看到有些在app.config.ts的內容已經可以直接注入在這裡,進行全局Application的注入
另外則是進行我們的Component的Inject的mock
  beforeEach(() => {
    mockSalesAgreementService = {
      updateSaleItem: jest.fn(),
    };
    windowSpy = jest.spyOn(window, 'window', 'get');
    fixture = TestBed.createComponent(SalesAgreementComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
至於我們的unit test則是可以這樣來做第三方套件的測試
  it('submit 發送訊號後跳出訊息', () => {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const messageServiceSpy = jest.spyOn(component['messageService'] as any, 'add');
    ...
    expect(messageServiceSpy).toHaveBeenCalledTimes(1);
  });
金天我們簡單講了Unit test 明天我們將會講講e2e test