BDD for XCUITest With Swift Protocols and Extensions
Learn how to apply BDD to your XCUITest UI testing for Swift code to make it more human-readable.
Join the DZone community and get the full member experience.
Join For FreeIn the last post on DRY XCUITest with Base classes, we have abstracted our code in the base classes in order to avoid the duplication of the code. We have achieved this using the object-oriented inheritance approach. However, Swift is a protocol-oriented language, and we will see how we can use Swift protocols and extensions to make our XCUITests more human-readable. We will apply Behavior-Driven Development, a.k.a BDD, in the methodology of our XCUITest.
BDD in Swift
The concept of BDD has been widely applied with Cucumber in Ruby and many other languages but BDD in Swift was always challenging because of a lack of proper BDD tools like Cucumber for Ruby, SpecfFlow for .NET, or Behat for PHP. There are libraries like XCTest-Gherkin and Cucumberish available to achieve BDD for iOS projects, but they are not as powerful as those for other languages. It’s still possible to make great use of native Swift features like protocols, extensions, and enumerations while writing acceptance tests in BDD style. We can use Swift’s protocol-oriented approach to write BDD style tests by capturing intended behavior in the form of Swift Protocol which is similar to the Features format in Gherkin. We can then think of all possible scenarios in the form of XCTest test methods which is similar to scenario titles in the Gherkin. We can also write steps in the form of methods in Given/When/Then a.k. a GWT using Swift extensions.
XCUITest BDD in Action
In our XCUITest101 app, we have a test already written to verify the welcome message. Now we will add another test in BDD or human-readable format like this:
func testWelcomeMessageInBDDStyle() {
givenILaunchedAnApp()
whenITapOnEnter()
thenIShouldSeeWelcomeMessage()
}
At this point, Xcode will give all the red errors use of unresolved Identifier givenILaunchedAnApp
, which means we have to implement the steps to make it pass and do actions or assertions. Now, we will create another file inside the XCUITest101UITest target and call it WelcomeStepDefinitions.swift
, as shown below.
We have to implement all these steps in the Swift extension, and we can write an extension on top of the XCUITestBase class as shown below:
extension XCUITestBase {
func givenILaunchedAnApp() {
app.launch()
}
func whenITapOnEnter() {
app.buttons["enter"].tap()
}
func thenIShouldSeeWelcomeMessage() {
XCTAssert(app.staticTexts["Welcome to XCUITest"].exists)
}
}
As you can see, in this extension, we have implemented all of our steps using the XCUITest methods that we used in the WelcomeMessage()
test. Now, if you run the test, all the tests will pass.
Sprinkle Activities for Better Test Reporting
Now that we have applied the BDD concepts to our XCUITests to make them human-readable, we can make them more readable in the Xcode reports by applying the XCTActivity feature of XCTest for each step. With activities sprinkled on each step, we can write steps like this:
func givenILaunchedAnApp() {
XCTContext.runActivity(named: "Given I Launched an App") { _ in
XCUIApplication().launch()
}
}
We can apply this to all the remaining steps. Once we have implemented all the activities, our step definition file looks like this:
Once you run this test, jump to the Xcode test report by right-clicking on the Play button from the test method. You will see the Xcode reports in a much more readable format.
Now our XCUITest and Xcode test reports are much more readable since we’ve applied extensions.
Add Protocols
Swift protocols are similar to the interfaces or abstract classes from other languages. We can use Swift protocols to make contracts between test classes and test methods. Writing protocols is an optional step but it’s good to have it. In our case, we can write a protocol for the Welcome
feature in the step definition file, which defines the test methods and makes the test class to adopt the protocol.
protocol Welcome {
func testWelcomeMessage()
func testWelcomeMessageInBDDStyle()
}
Now we can make our test class XCUITest101UITests class to adopt the Welcome
protocol. The benefit of creating protocols is you can think of all the test scenarios well in advance and create the contract with your test classes. There is less possibility of forgetting the scenarios to implement.
Try It Yourself
The source code used in this tutorial is available in the GitHub XCUITest101 repository and the protocol-bdd
branch here. Download the repository and explore the XCUITest with protocol and extension. From the command line, you can get the source code.
$ git clone https://github.com/Shashikant86/XCUITest101
$ cd XCUITest101
$ git checkout protoc0l-bdd
$ open XCUITest101.xcodeproj/
Once the project is opened in the Xcode 10, press CMD+U to run the XCUITest.
Conclusion
In this post, we have applied the Behavior-Driven Development approach to make our XCUITest tests human-readable, scalable, and reusable for iOS app testing. We can reuse the step definition anywhere in the UI test target and create human-readable Xcode reports. However, we have our XCUIElements in the step definitions, which need to be scaled for reusability. In the next post, we will organize UI elements using Swift enumeration for better maintenance of XCUITests. Stay tuned.
Published at DZone with permission of Shashikant Jagtap, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments