Transcripted Summary

In the last chapter, we implemented a base class for our XCUI test. We can add more functionality to base class as our test code grows. But in this chapter, we will add a similar sort of test, but using Behavior Driven Development methodology, or BDD.

In BDD we write failing tests using “Given/When/Then” format and then we write step definitions or code to make our steps pass.

So, in our example, we will write a new test by clicking on “TAUUTests” target, adding a new file. Let's add a Swift file, let's call it “BDDTest”, and make sure it's in “TAUUTests” target.

We have a file here. First, let’s import the XC test framework. Now we need to write a class and a test name with given/when/then steps so, we can define a class something like this — where we have a test method name, which is a meaningful name and we have a few given/when/then steps in a human readable or in plain English. This is not the feature files syntax that you might have seen in Cucumber framework, but we can use similar sort of human readable language in swift.

import XCTest

class BDDTest: TAUUITestBase {

 func testThankYouMessageInBDStyle() {
        givenAppIsReady()
        whenIEnter(city: "London")
        whenIEnrolled()
        thenIShouldSeeThankYouMessage()
    }
}

We have defined our test method with given/when/then steps. You can see that steps are fairly readable, and you can imagine what they can do. At the moment, Xcode is complaining because Xcode don't know anything about this given/when/then steps. We need to write something called Swift Extension. Extensions are basically a way to provide additional information for existing type.

Now we can add extension on our base class and implement all these functions inside the extension. Let's add extension, and let's write the functions, just blank functions, and we will write some code to implement those functions.

// extension with blank functions

extension TAUUITestBase {
    func givenAppIsReady() {
    }
    func whenIEnter(city: String) {
        }
    func whenIEnrolled() {
        }
    func thenIShouldSeeThankYouMessage() {
        }
}

Let's take one step at a time — let's implement “givenAppIsReady”.

You can say that when the enroll button is there when app is launched, then we can pretty much sure that our app is ready for test execution. We can easily write an assertion that enroll button exist, that means our app is now ready and we can continue our test execution.

func givenAppIsReady() {
    XCTAssertTrue(app.buttons["enrollButton"].exists)
}

Next step, we need to enter a city.

In the second chapter we have seen that to enter a city we first need to tap on the enter field, and then type the city. At the moment we are passing a city as the string parameter to this function, so whatever city we entered in this function here, that will be taken in our steps. We can write the steps something like this that we have seen already, where we can tap into the city test field, and then we can type the city which is coming from this parameter.

func whenIEnter(city: String) {
    app.textFields["city"].tap()
    app.textFields["city"].typeText(city)
}

Now we have typed the city, then we have to press the enroll button.

Enroll button can be tapped using the “enrollButton” tap method.

func whenIEnrolled() {
    app.buttons["enrollButton"].tap()
}

Once we tap the enroll button, then last thing we probably need to do is assert that the thank you message exists. We already done this test as part of our previous chapter, we are just putting it into the given/when/then function format.

func thenIShouldSeeThankYouMessage() {
    XCTAssertTrue(app.staticTexts["Thanks for Joining!"].exists)
}

Now we have almost implemented our steps. Xcode is now happy, there's no more errors.

Let's try and run this test now. Let's press Play button. Let's see the test running in the simulator.




Now our test succeeded, and we can see that we have achieved similar sort of result, but now our test looks more readable.

You can jump to the report, so basically you can click on the play button, right click and jump to the report. So you can see the Xcode report, showing all the events. As you can see that Xcode has generated that report.

Unfortunately, we can't make this report bigger, but we can see that Xcode is reporting the taps and the find city... then tapping the enroll button etc

We can make this Xcode report much better by using a thing called XCTActivity.

In order to make the Xcode report more readable, like in a BDD format, we can sprinkle the activity using: XCTContext.runActivity.

This is a method we have to sprinkle everywhere where we have written the steps. We can keep a string, which is like a readable name, so now I can give here "Given App is ready”.

And we have to pass the block here. Block basically takes the activity result, which we don't care so in Swift we can omit the parameter by using underscore, and then our proper step definition codes inside that. So, I'll just cut it, and paste it. Let me just add activities, and connect all our activities here, to all of our steps.

import Foundation
import XCTest

class BDDTest: TAUUITestBase {

 func testThankYouMessageInBDStyle() {
    givenAppIsReady()
    whenIEnter(city: "London")
    whenIEnrolled()
    thenIShouldSeeThankYouMessage()
}

extension TAUUITestBase {

    func givenAppIsReady() {
        XCTContext.runActivity(named: "Given App is ready ") { _ in
            XCTAssertTrue(app.buttons["enrollButton"].exists)
        }
    }

    func whenIEnter(city: String) {
        XCTContext.runActivity(named: "When I enter city \(city) ") { _ in
          app.textFields["city"].tap()
          app.textFields["city"].typeText(city)
        }
    }

    func whenIEnrolled() {
        XCTContext.runActivity(named: "When I Enrolled ") { _ in
          app.buttons["enrollButton"].tap()
        }

    }

    func thenIShouldSeeThankYouMessage() {
        XCTContext.runActivity(named: "Then I Should See Thanks message ") { _ in
         XCTAssertTrue(app.staticTexts["Thanks for Joining!"].exists)
        }
    }

}

Let's re-run the test now, and once test is passed let's hit the report and see what's the difference between the report generated by Xcode previously and the Xcode reports when we sprinkled the activities.

So, the test succeeded, let's jump to the reports again. Let's expand report.

Now you can see that the reports are much readable, our given/when/then steps are showing as a top level. And then all the taps and everything is hidden under the activities. In this way we can make our Xcode report much, much more readable.

  • There are some tools where you can convert this Xcode reports into HTML format and display it on your hosted internal company server.

  • There are some other tools that you can use to display the XCUITest reports in HTML or JUnit format.

  • One of the popular tools is XCpretty which you can use when you run the XCUITest from command line.

That's it for this chapter. Just to recap…

  • We have written a brand new BDD style XCUI test with given/when/then steps.
  • We have used Swift Extension to implement our steps. Extensions are powerful because the steps implemented using Swift Extension can be reused anywhere across the UI test target.
  • We also sprinkled XCT activities to make the Xcode report much more readable.

In the next chapter we will be organizing XCUITtest in proper directory structure. I will see you there.



Resources