[英]Mock a SwiftUI view from another module
我正在嘗試測試一個 SwiftUI 視圖,該視圖在其主體中具有來自另一個模塊的子視圖:
import SwiftUI
import Abond
struct ProfileView: PresentableView, LoadedView {
@State var isLoading = true
public var body: some View {
Load(self) {
AbondProfile(onSuccess: self.onSubmitSuccess)
}
}
func load() -> Binding<Bool> {
ProfileApi.getProfileAccessToken() { result in
switch result {
case .success(let response):
Abond.accessToken = response.accessToken
case .failure(let error):
print("error getting token")
}
isLoading = false
}
return $isLoading
}
func onSubmitSuccess() {
print("success")
}
}
我的問題是:如果我想在沒有構建實際ProfileView
視圖的情況下測試AbondProfile
的生命周期,有沒有辦法模擬它? 如果這是一種普通方法,我會注入一個依賴項 object,但我不知道如何將其轉換為結構初始化程序。
Abond是一個Swift Package,所以我不能修改AbondProfile。 而且我更希望能夠對我的視圖代碼進行盡可能少的更改來測試它。 我正在使用 XCTest。
正如 David Wheeler 所說,“計算機科學中的任何問題都可以通過另一個層次的間接性來解決。”
在這種情況下,一種解決方案是通過泛型類型參數間接引用AbondProfile
。 我們在AbondProfile
ProfileView
struct ProfileView<Content: View>: PresentableView, LoadedView {
@State var isLoading = true
@ViewBuilder var content: (_ onSuccess: @escaping () -> Void) -> Content
public var body: some View {
Load(self) {
content(onSubmitSuccess)
}
}
blah blah blah
}
如果我們提供使用ProfileView
的默認初始化程序,我們不必更改 ProfileView 的當前AbondProfile
:
extension ProfileView {
init() where Content == AbondProfile {
self.init { AbondProfile(onSuccess: $0) }
}
}
struct ProductionView: View {
var body: some View {
ProfileView() // This uses AbondProfile.
}
}
在測試中,我們可以提供一個模擬視圖:
struct TestView: View {
var body: some View {
ProfileView { onSuccess in
Text("a travesty of a mockery of a sham of a mockery of a travesty of two mockeries of a sham")
}
}
}
我接受了另一個答案,因為它是一個更合適的解決方案,但我發現它實際上可以重新定義測試文件中的結構:
import XCTest
import Abond
import SwiftUI
// Mock for Abond.AbondProfile
public struct AbondProfile: View {
static var viewDidAppearCallback: (() -> Void)?
static var submit: (() -> Void)?
public init(onSuccess: (() -> Void)? = nil) {
AbondProfile.submit = onSuccess
}
public var body: some View {
Text(Abond.accessToken)
.onAppear {
AbondProfile.viewDidAppearCallback?()
}
}
}
class ProfileViewTests: BaseViewControllerTests {
private var viewController: UIViewController?
func testSucesss() {
let viewDidAppearExpectation = XCTestExpectation(description: "View did appear")
AbondProfile.viewDidAppearCallback = { viewDidAppearExpectation.fulfill() }
MockApi.mockRequest(ProfileApi.getProfileAccessToken, response: ProfileAccessToken(accessToken:"accessToken_123"))
initialize(viewController: UIHostingController(rootView: ProfileView()))
wait(for: [viewDidAppearExpectation], timeout: 10)
XCTAssertEqual(Abond.accessToken, "accessToken_123")
AbondProfile.submit!()
// etc.
}
}
我知道 static 變量會使測試變得脆弱——但除此之外,我很想知道是否有其他理由不這樣做。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.