DevUI是一支兼具設計視角和工程視角的團隊,服務於華爲雲DevCloud平臺和華爲內部數箇中後臺系統,服務於設計師和前端工程師。
官方網站:devui.design
Ng組件庫:ng-devui(歡迎Star)
官方交流:添加DevUI小助手(devui-official)
DevUIHelper插件:DevUIHelper-LSP(歡迎Star)css
做爲一個成熟的web前端工程師,咱們都熟知,編寫單元測試用例,對前端而言,確實收益不大,業務代碼還寫不完呢,寫什麼測試用例吶,大概這是諸多web前端工程師的現狀。html
那麼爲何我還要介紹單元測試用例編寫呢?前端
在開發側發現產品質量問題,對於開發來講,是成本最低的一種保證上線產品質量的方法。git
在開發時編寫測試用例,就是諸多從開發側發現問題的策略之一。github
在對devui組件庫進行單元測試用例編寫的時候,會考慮兩點:web
本文將以組件庫中的Button組件爲例,展開對於DevUI開源組件庫單元測試用例編寫的介紹。npm
先將ng-devui組件庫源碼克隆下來,安裝依賴包後保證npm start可以啓動項目:json
項目啓動後,前往package.json文件,能夠看到有兩個test命令:markdown
這個時候可能有些讀者有點懵逼,這兩個命令,我該運行哪一個呢?前端工程師
經過查看angular.json查看應該運行的命令,拉到angular.json文件底部,能夠查看到默認運行的是devui,項目中有三個項目:devui
、devui-e2e
、devui-lib
。
devui的根路徑是src
,devui-lib的根路徑是devui
,而DevUI組件庫的全部組件都在devui路徑之下:
根據上述判斷可知,DevUI組件庫的項目應該是devui-lib
。
所以咱們應該運行的package.json
中的test:lib
命令:
npm run test:lib
複製代碼
運行完npm run test:lib
命令,能夠看到DevUI組件庫包含666個單元測試用例,其中5個跳過,661個成功,0個失敗。
打開button組件的源碼目錄,點擊進入button的測試文件button.spec.ts,將遇到的第一個describe改寫成fdescribe,從新運行npm run test:lib
,此時會發現只有15個運行成功的用例,在button.spec.ts文件中搜索it,會發現有15個it字段。
實際上,一個it即爲一個單元測試用例,fdescribe表示,運行的時候只運行整個fdescribe下包含的it單元測試用例。
爲了保證文章的不那麼冗餘,這裏只拋磚引玉,僅對button的部分功能進行單元測試,瞭解了單元測試用例運行的基本方式以後,就能夠開始着手單元測試用例的編寫。
編寫前將現有的button.spec.ts文件內容刪除,以便咱們從0開始編寫單元測試用例。
編寫測試用例時,要先將button組件引入,其中,beforeEach表示每一個it單元測試用例執行前都會執行的操做。
@Component({
template: `
<d-button></d-button>
`
})
class TestButtonAutoFocusComponent {}
fdescribe('Button', () => {
let fixture: ComponentFixture<any>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ButtonModule],
declarations: [TestButtonComponent, TestButtonAutoFocusComponent]
}).compileComponents();
}));
...
});
複製代碼
這裏將會對button的基本樣式,common樣式、按鈕點擊功能及禁用狀態進行測試,所以,咱們會在TestButtonComponent測試組件中的button上加上樣式、是否禁用、點擊函數三個功能。
@Component({
template: `
<d-button [bsStyle]="style" (btnClick)="isClick()" [disabled]="disabled"></d-button>
`
})
class TestButtonComponent {
style = 'primary';
disabled = false;
hasClick = false;
isClick() {
this.hasClick = true;
}
}
複製代碼
爲了測試button相關的功能,咱們須要建立一個TestButtonComponent的實例,以後還要可以獲取到這個實例中使用到的button元素,測試時每每會用到四個變量。
let fixture: ComponentFixture<any>;
let testComponent: TestButtonComponent;
let buttonDebug: DebugElement;
let buttonNative: HTMLElement;
beforeEach((() => {
fixture = TestBed.createComponent(TestButtonComponent);
testComponent = fixture.debugElement.componentInstance;
buttonDebug = fixture.debugElement.query(By.css('d-button'));
buttonNative = buttonDebug.nativeElement;
fixture.detectChanges();
}));
複製代碼
爲了保證button組件沒有語法類的致命錯誤,首先應該可以保證組件實例可以建立成功,這也是咱們第一步須要進行的測試。
it('Button demo has created successfully', () => {
expect(testComponent).toBeTruthy();
});
複製代碼
保證button組件的樣式,則須要知道組件可以正確的應用到樣式類。
a) 經過查看button.component.html文件可知,正確的應用devui-btn,devui-btn-primary兩個類便可表示button可以正確應用到樣式類。這樣,只要樣式文件中的樣式類正確,樣式就正確。
b) 正確應用devui-btn,devui-btn-common兩個類即表示common類型的button樣式正確。
it('Button should apply css classes', () => {
let buttonHtml = buttonDebug.query(By.css('button'));
expect(buttonInsideNativeElement.classList.contains('devui-btn')).toBeTruthy();
expect(buttonInsideNativeElement.classList.contains('devui-btn-primary')).toBeTruthy();
testComponent.style = 'common';
fixture.detectChanges();
buttonHtml = buttonDebug.query(By.css('button'));
expect(buttonInsideNativeElement.classList.contains('devui-btn')).toBeTruthy();
expect(buttonInsideNativeElement.classList.contains('devui-btn-common')).toBeTruthy();
});
複製代碼
保證button功能正常,則須要知道點擊button後,可否觸發綁定的isClick事件,觸發click事件成功,則hasClick的值將由false變動爲true。
a)首先,咱們應該判斷一下hasClick的初始賦值是否正確;
b)接着,模擬點擊button按鈕所綁定的點擊事件。
it('Button click', () => {
expect(testComponent.hasClick).toBeFalsy();
let buttonHtml = buttonDebug.query(By.css('button'));
buttonHtml.nativeElement.click();
fixture.detectChanges();
expect(testComponent.hasClick).toBeTruthy();
});
複製代碼
對於disabled狀態下,點擊無效是其功能上的一大特色,同時disabled狀態的button具備disabled屬性,因此咱們的單元測試也是分爲兩個部分:
a)點擊失效
b) button元素具備disabled屬性
it('Button disabled should have disabled attribute', () => {
testComponent.disabled = true;
fixture.detectChanges();
// 點擊失效
expect(testComponent.hasClick).toBeFalsy();
let buttonHtml = buttonDebug.query(By.css('button'));
buttonHtml.nativeElement.click();
fixture.detectChanges();
expect(testComponent.hasClick).toBeFalsy();
// 具備disabled樣式
expect(buttonHtml.nativeElement.hasAttribute('disabled')).toBeTruthy();
});
複製代碼
(1)做爲前端開發,相信大多數開發都在業務開發中摸爬滾打,若是你遇到的業務對質量要求極高,任何一個重大事故均可能影響到諸多客戶,拉低客戶的效率,給客戶形成損失。這種狀況,你該如何保證你的代碼質量?
(2)還有一種情形,你開發任何一個小的組件,好比一個小小的按鈕,均可能會在幾十,上百個業務中使用,你的任何一個失誤,都有如落入湖水的石子,蕩起整個湖面的漣漪。
以上兩種情形,若是開發者沒有測試充分,貿然上線,都會形成重大損失。
穩定:是這兩種開發場景第一需求。
這個時候,但願上述單元測試用例的編寫可以對讀者有所啓發,固然啦,咱們最終的目標依然是以最小的成本解決更多的問題!
咱們是DevUI團隊,歡迎來這裏和咱們一塊兒打造優雅高效的人機設計/研發體系。招聘郵箱:muyang2@huawei.com。
文/DevUI 莫奈的關門弟子
往期文章推薦