본문 바로가기
Coding

ViewInspector에서 @State를 포함하는 SwiftUI 보기를 테스트하는 방법

by Jake Gyllenhaal 2022. 4. 18.
반응형

ViewInspector에서 @State를 포함하는 SwiftUI 보기를 테스트하는 방법

 

간단하지만 강력한 SwiftUI 트릭

Unsplash의 Sigmund 사진

SwiftUI 테스트를 아주 잘 시작하려면 다음을 사용하십시오. ViewInspector 프레임워크, 이것 또는 이것을 읽을 수 있습니다.

첫 번째 자습서(및 ViewInspector GitHub 페이지)에 설명된 항목 중 하나는 @State 테스트하려는 보기에서.

기본적으로 보기가 다음과 같은 경우:

struct ContentView: View {
@State var numClicks:Int = 0
var body: some View { VStack{ Button("Click me"){ numClicks += 1 }.id("Button1") Text("\(numClicks)") .id("Text1") .padding() } } }  

실제로 버튼을 클릭하는 동작을 테스트하는 것은 불가능합니다. numClicks. 허용되는 해결 방법은 뷰에 약간의 코드를 추가하여 기본적으로 다음과 같이 변환하는 것입니다.

struct ContentView: View {
@State var numClicks:Int = 0
internal let inspection = Inspection()
var body: some View { VStack{ Button("Click me"){ numClicks += 1 }.id("Button1") Text("\(numClicks)") .id("Text1") .padding() }.onReceive(inspection.notice) { self.inspection.visit(self, $0) } } }  

여기서 검사는 다음과 같습니다.

internal final class Inspection {
let notice = PassthroughSubject<UInt, Never>()
var callbacks: [UInt: (V) -> Void] = [:] func visit(_ view: V, _ line: UInt) {
if let callback = callbacks.removeValue(forKey: line) {
callback(view)
}
}
}extension Inspection: InspectionEmissary {}

보시다시피 ContentView 새 Inspection 속성이 있고 해당 본문의 onReceive는 데이터가 주목받는 게시자에게 게시될 때 Inspection 속성의 방문 메서드를 실행하도록 지시됩니다.

이렇게 하면 문제가 해결되고 작동하는 테스트 케이스는 다음과 같이 보일 수 있습니다.

func testContentView() throws{
let sut = ContentView()
_ = sut.inspection.inspect { view in
let button = try view.find(viewWithId: “Button1”).button()
try button.tap()
XCTAssertEqual(try view.actualView().numClicks, 1)
let text = try view.find(viewWithId: “Text1”).text()
let value = try text.string()
XCTAssertEqual(value, “1”)
}
}

그러나 프로덕션 코드에 테스트 '기능'을 추가하는 것은 보기 흉합니다. 복잡한 보기를 훨씬 더 복잡하게 만들 수 있으며 테스트하려는 각 보기에서 복사/붙여넣기가 필요한 중복 코드가 많이 있습니다.

따라서 테스트 코드에 약간의 오버헤드를 추가하지만 실제 보기 구현은 그대로 두는 더 깔끔한 것을 찾으려고 했습니다.

먼저 간단한 래퍼 보기를 구현했는데, 이는 다음에 의해 필요한 검사 기능을 추가할 수 있습니다. ViewInspector:

public let TEST_WRAPPED_ID: String = “wrapped”struct TestWrapperView : View{
internal let inspection = Inspection()
var wrapped: Wrapped
init( wrapped: Wrapped ){ self.wrapped = wrapped } var body: some View { wrapped .id(TEST_WRAPPED_ID) .onReceive(inspection.notice) { self.inspection.visit(self, $0) } } }  
extension TestWrapperView: Inspectable{}

이 래퍼 보기를 사용하면 의 원래 구현을 사용하여 보기를 테스트할 수 있습니다. ContentView:

func testContentView() throws{
let sut = TestWrapperView(wrapped: ContentView())
_ = sut.inspection.inspect { view in
let wrapped = try view.find(viewWithId: TEST_WRAPPED_ID)
let button = try wrapped.find(viewWithId: “Button1”).button()
try button.tap()
let numClicks = try wrapped
.view(ContentView.self)
.actualView()
.numClicks
XCTAssertEqual(numClicks, 1)
let text = try wrapped.find(viewWithId: “Text1”).text()
let value = try text.string()
XCTAssertEqual(value, “1”)
}
}

SwiftUI 보기 테스트를 좀 더 쉽게 만들어주는 이 작은 트릭이 마음에 드셨으면 합니다.

반응형

댓글