Last active
October 24, 2023 15:13
-
-
Save kkebo/29730032caa0ee4c4686497e987bb46f to your computer and use it in GitHub Desktop.
SwiftUI のプレビュー上でユニットテストを実行する Proof of Concept (ContentView のテストをしたい場合)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ContentView: View { | |
@State var hoge = 0 | |
@Environment(\.testCaseNumber) private var testCaseNumber | |
func change() { | |
hoge = 3 | |
} | |
var body: some View { | |
VStack { | |
Image(systemName: "globe") | |
.imageScale(.large) | |
.foregroundColor(.accentColor) | |
Text("Hello, world!") | |
} | |
.modifier(TestModifier(testCase: allTestCases[testCaseNumber])) | |
} | |
} | |
extension ContentView { | |
var allTestCases: [TestCase] { | |
[ | |
test1, | |
test2, | |
] | |
} | |
var test1: TestCase { | |
.init(label: "hoge == 0") { | |
.init(success: hoge == 0) | |
} | |
} | |
var test2: TestCase { | |
.init(label: "hoge == 3") { | |
change() | |
return .init(success: hoge == 3) | |
} | |
} | |
} | |
#Preview { | |
VStack { | |
// FIXME: 個数はどこから持ってくる? | |
ForEach(0..<2, id: \.self) { i in | |
ContentView() | |
.environment(\.testCaseNumber, i) | |
} | |
} | |
.environment(\.isTesting, true) | |
} | |
struct TestCase: Identifiable { | |
var id: UUID = .init() | |
var label: String | |
var run: () -> TestResult | |
} | |
struct TestResult { | |
var success: Bool | |
} | |
struct IsTestingKey: EnvironmentKey { | |
static let defaultValue: Bool = false | |
} | |
extension EnvironmentValues { | |
var isTesting: Bool { | |
get { self[IsTestingKey.self] } | |
set { self[IsTestingKey.self] = newValue } | |
} | |
} | |
struct TestCaseNumberKey: EnvironmentKey { | |
static let defaultValue: Int = 0 | |
} | |
extension EnvironmentValues { | |
var testCaseNumber: Int { | |
get { self[TestCaseNumberKey.self] } | |
set { self[TestCaseNumberKey.self] = newValue } | |
} | |
} | |
struct TestModifier: ViewModifier { | |
let testCase: TestCase | |
@Environment(\.isTesting) private var isTesting | |
@State private var result: TestResult? | |
func body(content: Content) -> some View { | |
if isTesting { | |
VStack { | |
if let result { | |
Text("\(testCase.label): \(result.success ? "passed" : "failed")") | |
} else { | |
Text("Running") | |
} | |
} | |
.onAppear { | |
result = testCase.run() | |
} | |
} else { | |
content | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
テストケース記述の自由度を上げようと思ったらもうちょっと考える必要あり