所有代碼都必須被單元測試覆寫。
每次測試測試一件事(在一個 it 裡實作)。
單元測試将被測試的代碼與其依賴項隔離:模拟所有的依賴項。
單元測試需要互相獨立:我們應該能夠以任何順序從檔案運作測試,并且不會改變結果。
在适用時涵蓋快樂路徑、錯誤、邊緣情況和 UI。
UI Components
Mock Everything
與任何其他代碼段一樣,我們希望單獨測試 UI 元件。 我們不希望測試結果受到我們正在測試的類之外的代碼的影響。
雖然模拟服務之類的依賴關系更為明顯,但很容易忘記模拟從測試元件的模闆中調用的子元件。
要模拟子元件,您可以在規範檔案中建立它的假副本。 僞造元件必須與您要僞造的子元件具有相同的選擇器:
例子:
@Component({
template: '',
selector: 'cx-some-component'
})
class MockSomeComponent {
@Input() someparam;
}
Then, you declare it in the TestBed:
TestBed.configureTestingModule({
imports: [
...
],
declarations: [MockSomeComponent],
providers: [
...
],
}).compileComponents();
NGRX and Tests That Use the Store
事實證明,模拟 NGRX 商店是一項相當大的挑戰。 NGRX 存儲是我們單元測試中模拟依賴項規則的例外。
要對從 store 讀取的一段代碼執行單元測試,請通過使用資料顯式調用相關成功操作來填充 store 以設定測試。
這是我們排程 LoadUserAddressesSuccess 來設定測試資料的示例:
it('should be able to get user addresses', () => {
const mockUserAddresses: Address[] = [{ id: 'address1' }, { id: 'address2' }];
store.dispatch(new UserActions.LoadUserAddressesSuccess(mockUserAddresses));
let addresses: Address[];
service
.getAddresses()
.subscribe(data => {
addresses = data;
})
.unsubscribe();
expect(addresses).toEqual([{ id: 'address1' }, { id: 'address2' }]);
});
Avoiding Silently Failing Tests
最好的做法是删除訂閱之外的斷言。 這樣,我們確定在測試完成之前執行斷言。 為了斷言 observable 的結果,我們在訂閱中配置設定結果,但斷言是在訂閱之外用值完成的。
下列做法不推薦:
service
.getAddresses()
.subscribe(addresses => {
expect(addresses).toEqual([{ id: 'address1' }, { id: 'address2' }]);
})
.unsubscribe();
});