[英]Angular Unit Testing - How to test a service which creates a Websocket
我需要為以下代碼編寫單元測試:
getSomething(id: string): Observable<State | null> {
return new WebSocketSubject(webSocket(`ws://<websocket>`)
.pipe(
catchError(err => {
console.error('Error in WebSocket connection: ', err);
return concat(
of(null),
throwError(err)
);
}),
retryWhen(errors =>
errors.pipe(
delay(1000)
)
)
)
);
}
我想寫兩個測試:
我寫了第一個測試如下,但我不知道這里會發生什么:
it('should get Something create websocket', () => {
service.getSomething('test').subscribe(
data => expect(data).toBeInstanceOf(webSocket),
fail
);
});
歡迎您的意見。 謝謝。
很難提供一個例子作為評論,所以,這里有完整的答案。
這就是我所說的:
@Injectable()
class WebSocketFactory {
createWebSocket<T>(url: string): WebSocketSubject<T> {
return webSocket(url);
}
}
class SomeClass {
constructor(private readonly factory: WebSocketFactory) {
}
getSomething(id: string): Observable<State | null> {
return this.factory.createWebSocket(`ws://<websocket>`).pipe(
catchError((err) => {
console.error("Error in WebSocket connection: ", err);
return concat(of(null), throwError(err));
}),
retryWhen((errors) => errors.pipe(delay(1000)))
);
}
}
如您所見,我已將 websocket 創建抽象為一個微型服務WebSocketFactory
,這為我們帶來了以下好處(注意:這不是一個隨時可以重用的代碼,請閱讀下文):
describe('SomeClass', () => {
let subject = new Subject<any>();
let service: SomeClass;
beforeEach(() => {
service = new SomeClass({
createWebSocket: <T>() => subject as WebSocketSubject<T>,
});
});
it('should do something useful', () => {
subject.next(/* something */);
service.getSomething('test').subscribe(
data => expect(data).toBeEqual(/* something */),
fail
);
});
});
如您所見,現在您可以完全控制臨時 websocket 創建的時間和方式,您可以訪問內部結構,您可以發送任何值,提前關閉它等等——只需使用subject
,而不是真正的WebSocket
對象。
現在,有一些注釋、警告和提示。
上面的測試代碼不起作用,它只是說明了這一點。 為了使其工作,您需要實際設置 observable 測試,由於 observable 的異步性質,這相當重要。 這是一個很大的話題,我會從一些像這樣和這樣的文章開始。
我正在使用一個臨時模擬的東西(通過包裝subject
實現 WebSocketFactory 的對象文字),但有些東西使這更容易和更強大: spies 。 但這本身就是一個很大的話題。
上面的例子很簡單,但如果你的代碼復雜得多,你可能想要使用TestBed
提供的TestBed
( docs ) 類並進行提供者覆蓋,而不是手動創建實例。
顯然webSocket
返回WebSocketSubject
( docs ),因此,我相應地調整了代碼。
除了提供完整的類作為工廠之外,您還可以只使用一個函數(類似於constructor(private readonly webSocket: typeof webSocket) {}
,甚至是constructor(@Optional() private readonly webSocket: typeof webSocket = webSocket) {}
),我只是一般喜歡來包裝類的東西更容易擴展,如果將來的某個任務,要求它。
我知道這不是一個完整的答案,因為它沒有直接解決您的“我不知道這里會發生什么”——那是因為您遇到了相當復雜的一組混合在一起的主題:依賴倒置——通過抽象來簡化websocket 創建、rxjx/observable 測試(甚至一般的異步操作測試)、單元與功能/集成測試。 這些主題中的每一個都相當龐大,但我希望上面的所有鏈接都能幫助您入門。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.