It is sometimes useful to navigate to a child View from multiple links, initializing the child View differently in each navigationLink. Since the same child View is being used it would be convenient to have a single XCTestCase class that tested the child View's UI features. I think this requires me to automatically re-run the XCTestCaseClass while varying the class's properties for each run. It isn’t obvious how to do this.
The minimum example is shown below. The project was named UITestWithPropertyVariables. The ContentView (left) has a navigation link labeled "One Greeting" and a second link labeled "Three Greetings". An example of "Three Greetings" display is shown on the right. Both links call the same child View, named HelloWorld. This View has a greetings property indicating how many times “Hello World” should be displayed. This property is set to 1 in the first link and to 3 in the second link.
Screen Shot
Of course, I could write two different UITestCase classes that have the greetings property hard coded, as shown below under Sample UITest. That would mean duplicating the test code. In this minimum example the test code only counts the number of Text Views, which isn't much of a burden. But a real world app would have extensive testing of the child view and duplicating that test logic seems inefficient and hard to maintain. Is there a better way?
ContentView
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Spacer()
// First link to HelloWorld
NavigationLink(
"One Greeting",
destination: HelloWorld( greetings: 1 ) )
Spacer()
// Second link to HelloWorld
NavigationLink(
"Three Greetings",
destination: HelloWorld( greetings: 3) )
Spacer()
}
.padding()
.navigationTitle("Test Of Reused Scenes")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
HelloWorld
import SwiftUI
struct HelloWorld: View {
var greetings = 1
var body: some View {
VStack {
ForEach( 0 ..< greetings )
{ greeting in
Text( "Hello World #\(greeting + 1)")
}
}
}
}
struct ReusableHelloWorld_Previews: PreviewProvider {
static let numberGreetings = 3
static var previews: some View {
HelloWorld( greetings: numberGreetings )
}
}
Sample UITest (but having hard-coded, non-varying properties)
import XCTest
final class UITestWithPropertyVariables: XCTestCase {
// Hard-coded properties (those that I'd like to vary automatically in UITests)
let navigationText = "Three Greetings"
let expectedGreetings = 3
// non-varying properties
let app = XCUIApplication()
override func setUpWithError() throws {
app.launch()
continueAfterFailure = false
}
func testExample() throws {
// navigate to a scene based on the varying properties
let navigationButton =
app.buttons[ navigationText ]
XCTAssert( navigationButton.isHittable )
navigationButton.tap()
// check that the greeting appears the expected number of times,
// again basing the test on the varying properties
let helloWorldPredicate = NSPredicate(format: "label beginswith 'Hello World'")
let greetingTexts =
app.staticTexts.matching( helloWorldPredicate )
XCTAssert( greetingTexts.count == expectedGreetings )
}
}
