我正在嘗試為使用服務執行 HTTP 請求以從資料庫中檢索資訊的組件設定一些單元測驗。我對角度和單元測驗非常陌生,所以請耐心等待。在我的測驗中,我試圖監視名為的函式getClients(該函式本質上是實際執行 HTTP 請求的服務的處理程式)并使用callFake.
我遇到的問題是該getClients功能沒有被覆寫,這使我相信間諜不起作用或沒有監視我認為的內容。我可以說它沒有被呼叫,因為失敗訊息參考了真實getClients函式中的某些內容。
測驗代碼:
我的理解是,因為我試圖監視的函式在ngOnInit函式中,所以我必須先定義間諜,然后實體化組件。我也試過在里面運行間諜it,但也沒有用。
describe('handleID', () => {
beforeEach(waitForAsync (() => {
spyOn(service, 'getClients').and.callFake(() => {
let companyList = [
{
COMPANYDESCRIPTOR: "Hello World Inc.",
COMPANYNAME: "Hello World Inc.",
CUSTOMERID: "abcdef123456",
CUSTOMERKEY: 123456
}
]
component.companySearchService.companies.next(companyList);
return companyList;
});
fixture = TestBed.createComponent(CompanySearchComponent);
component = fixture.componentInstance;
service = component.companySearchService;
fixture.detectChanges();
}));
it("should update component.companyForm.controls['selectedCompany'] to 'Hello World Inc.'", () => {
component.companyForm = component._formBuilder.group({
selectedCompany: ['']
})
component.pathToNameProp = 'COMPANYNAME';
component.pathToIdProp = ['CUSTOMERID', 'CUSTOMERKEY'];
let id = 123456;
component.handleID(id);
expect(component.companyForm.get('selectedCompany')).toBe('Hello World Inc.');
})
})
實際功能:
為了清楚起見,我提供了getClients以下功能。dbService是進行 API 呼叫的資料庫服務。makeAnApiCall回傳一個observable并且subscribe只是將資料傳遞給另一個處理程式,該處理程式根據source.
getClients(endpoint, method, options = []) {
this.loading.next(true);
this.dbService
.makeAnApiCall(endpoint, method, options)
.subscribe(
res => this.generateCompanyList(res, this.source.getValue())
)
}
失敗訊息:
失敗訊息參考了從資料庫服務的makeAnApiCall方法回傳的可觀察訂閱。這讓我相信間諜根本不是被創造出來的,或者完全是在監視其他東西。
Failed: Cannot read properties of undefined (reading 'subscribe')
at CompanySearchService.getClients (http://localhost:9876/_karma_webpack_/main.js:6343:13)
at CompanySearchComponent.ngOnInit (http://localhost:9876/_karma_webpack_/webpack:/src/app/utilities/company-search/company-search.component.ts:98:39)
...
問題:
- 為什么間諜不起作用?
- 關于單元測驗,在處理不需要完全避免它們的可觀察物件、承諾和 HTTP 請求時,是否有更好的方法來撰寫單元測驗?
提前感謝您的任何幫助!
uj5u.com熱心網友回復:
據我所知,您TestBed.configureTestingModule在創建組件之前缺少做 a 。這需要宣告被測組件并提供類似于普通 ngModule 的服務。最好查看Angular 測驗指南以了解如何使用它。
在測驗模塊中,您將在 providers 陣列中設定 CompanySearchService,然后您可以使用TestBed.inject(CompanySearchService)并模擬您想要的方法來訪問它。
uj5u.com熱心網友回復:
這個解決方案解決了我的問題,但它仍然沒有真正回答我的問題。因此,如果有人可以對此有所了解,我很樂意將他們的回答標記為已接受的答案。
單元測驗
它看起來像我呼叫spyOn,的順序fixture.detectChanges,并且component.ngOnInit弄亂了服務,因此弄亂了我的Cannot read properties of undefined錯誤。下面更新的代碼是完整的單元測驗。我創建了__beforeEach這樣我就不必重復嵌套單元測驗中的所有內容。我最終也完全取消了呼叫component.ngOnInit(),因為它似乎detectChanges也同樣有效。
describe('CompanySearchComponent', () => {
let fixture, component, service;
let __beforeEach = () => {
fixture = TestBed.createComponent(CompanySearchComponent);
component = fixture.componentInstance;
service = component.companySearchService;
component.companySource = 'database';
spyOn(service, 'getClients').and.callFake(() => {
let response = { data: { rows:[
{
COMPANYDESCRIPTOR: "Hello World Inc.",
COMPANYNAME: "Hello World Inc.",
CUSTOMERID: "abcdef123456",
CUSTOMERKEY: 123456
}
]}}
component.companySearchService.generateCompanyList(response, 'database');
});
fixture.detectChanges();
}
beforeAll(waitForAsync(__beforeEach));
it ('should initialize the component and the service', () => {
expect(component).toBeDefined();
expect(service).toBeDefined();
})
it ('should initalize pathToNameProp to \'COMPANYNAME\' and pathToProp to [\'CUSTOMERID\', \'CUSTOMERKEY\'] with source set to \'database\'', () => {
expect(component.pathToNameProp).toBe('COMPANYNAME');
expect(component.pathToIdProp).toEqual(['CUSTOMERID', 'CUSTOMERKEY']);
})
it ('should update companies array', () => {
expect(component.companies).toEqual([
{
COMPANYDESCRIPTOR: "Hello World Inc.",
COMPANYNAME: "Hello World Inc.",
CUSTOMERID: "abcdef123456",
CUSTOMERKEY: 123456
}
]);
})
describe('handleID', () => {
beforeAll(waitForAsync(__beforeEach));
it("should update selectedCompany form'", () => {
let id = '123456';
component.handleID(id);
expect(component.companyForm.controls['selectedCompany'].value.COMPANYNAME).toBe('Hello World Inc.');
})
})
})
設定源
它可能不相關,但我想提出另一個我遇到的問題。該組件不是獨立的,其他組件將其作為依賴項匯入。也就是說,必須顯式定義companySearchComponent.companySource然后重新初始化組件,因為它的值是在建構式中定義的。
constructor(
private elem: ElementRef,
public companySearchService: CompanySearchService,
private hierarchyService: HierarchyService,
private _formBuilder: FormBuilder
) {
this.companySource = this.elem.nativeElement.dataset.companySrc;
this.prevCompanySrc = this.companySearchService.source.getValue();
}
建構式參考源的選擇器元素
<company-search [hidden]="!showSearch" id="company-search" data-company-src="database"></company-search>
在companySearchComponent.ngOnInit該源值內部,用于定義 http 請求和回應的一些重要屬性。它也用于初始呼叫companySearchService.getClients()(我最初遇到問題的函式)。
ngOnInit() {
switch(this.companySource) {
case 'database':
...
this.pathToNameProp = 'COMPANYNAME';
this.pathToIdProp = ['CUSTOMERID', 'CUSTOMERKEY'];
break;
...
default:
break;
}
if (!this.companySearchService.companies.value || this.prevCompanySrc !== this.companySource) {
this.companySearchService.source.next(this.companySource);
this.companySearchService.getClients(this.endpoint, this.httpMethod, this.httpOptions);
}
...
}
就像我說的那樣,這并不能完全回答我提出的問題,但它是解決問題的方法,所以如果有人發布更全面和徹底的解決方案,我很樂意將其標記為已接受的答案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/483076.html
