Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Introducing Protocol-Oriented BDD in Swift for iOS Apps: Part 1

DZone's Guide to

Introducing Protocol-Oriented BDD in Swift for iOS Apps: Part 1

In this step-by-step tutorial, see how to use Swift protocols, extensions, and enumerations with Behavior Driven Development, or BDD, in iOS mobile apps.

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

Swift is truly a protocol-oriented language. Since it was introduced in WWDC 2014 and open sourced in December 2015, it has become one of the most popular languages for developing iOS applications. You can watch this WWDC video to know about protocol-oriented programming with Swift. In the recent days, the protocol-oriented approach is definitely dominating the object oriented approach, at least for Swift. It means we have to gradually forget about writing classes and start writing protocols instead. In this detailed and step by step blog post, we will see how to drive development from behavior, a.k.a BDD, using Swift protocols, extensions, and enumerations.

BDD+Swift+XCTest

Behaviour Driven Development a.k.a BDD in the Swift or iOS development world is always challenging because of lack of proper BDD tools like Cucumber for Ruby, SpecFlow for .NET or Behat for PHP. There is a Swift library  XCTest-Gherkin from Net-A-Porter group and objective-C library  Cucumberish from Ahmed Ali, which are available for iOS development to achieve BDD but they are not as powerful as from other languages. It’s still possible to make great use of Swift features like protocols, extensions and enumerations while writing acceptance tests or doing Behaviour Driven Development a.k.a BDD. We will explore that option in detail in this post.

BDD Concepts

Just in case you are new to BDD a.k.a Behaviour Driven Development is a process of bridging the communication gap between technology and business people using the same language so that business people can contribute to specification and programmers can use those specifications to write the code.

BDD is a term coined by Dan North to overcome the pitfalls in Test Driven Development and bridge the communication gap between business and technology. In a summary, it works like this:

  • Write some user stories collaboratively with the team.
  • Capture the intended behavior in the form of features before writing any code. Refer to the story format here.
  • Think of all possible scenarios that cover the intended functionality, reducing the risk of creating bugs. Write a scenario title and write steps in the domain specific language (DSL) or human-readable format like Gherkin.
  •  Implement the behavior in the form of step definitions. You can refer to the step definition sample here.
  • Passing scenarios verify that the implementation of the behaviour has been successful.

I assume that you probably aware of BDD process and we will jump straight into the topic.

Protocol Oriented BDD

At this point, we have basic BDD concepts; let’s apply those principles in a Protocol Oriented way.

  • Write requirements collaboratively with the team anywhere in JIRA, Spreadsheet, or something similar.
  • Capture intended behavior in the form of Swift Protocol which is similar to the Features format in Gherkin.
  • Think of all possible scenarios in the form of XCTest test methods which is similar to scenario titles in the Gherkin.
  • Write an XCTest class conforming to protocol; we need to implement all the requirements in our tests.
  • Write steps in the form of methods inGiven/When/Then, a.k. a GWT-like format e.g givenIAmOnTheHome Screen() . 
  • Implement steps as an extension to the protocol defined for the particular feature.
  • Abstract UI elements in the form of enumeration for the particular feature.

Now that we have an idea how to implement BDD steps in a protocol-oriented way, let’s dive into the code.

Protocol Oriented BDD in Action

Let’s build an app which greets users when the press the Greet button, using a protocol-oriented BDD approach. The app has following main requirements:

  • The app should have a home screen with a Greet button.
  • When the user presses the Greet button, they should see the welcome message. ‘Welcome to POP.’

That’s a very simple application. It’s time to dive into Xcode to build this app.

  • Fire up Xcode and create new project -> iOS -> Single View Application.
  • Name the application as ‘Greeter.’
  • Select the box ‘Include UI Tests.
  • Open the  GreeterUITest.swift  file and delete the comments to make it bit cleaner.

Write a Protocol

Now we have template code for our new app. We also have our requirements ready. Let’s write a protocol in the UI test target so that we can list all the requirements for the Greeter feature. Create a new file called  Greeter+Protocol.swift  and add our requirements.

protocol Greetable {

    func testHomeScreenHasGreetButton()
    func testUserShouldGetWelcomeMessageOnceEntered()

}


Let’s make our test GreeterUITest.swift to confirm to Greetable protocol; that means we must have those methods in the XCUITest class in order to compile the test target. Let’s add them so that our test file will look like this:

import XCTest

class GreeterUITests: XCTestCase, Greetable {

    override func setUp() {
        super.setUp()
        continueAfterFailure = false
    }

    override func tearDown() {
        super.tearDown()
    }

    func testHomeScreenHasGreetButton() {

    }

    func testUserShouldGetsWelcomeMessageOnceEntered() {


    }
}


What we have done so far can be seen in the GIF below:

Write Given/When/Then Steps in The Extension

At this point, we wrote scenario titles in terms of XCTest methods. Now, it’s time to write Given/When/Then, a.k. a GWT and start implementing it. Remember, we don’t necessarily have to follow Gherkin syntax here, so feel free to use any format similar to GWT. We will write some GWT in the test methods which looks like this:


func testHomeScreenHasGreetButton() {
   givenTheAppIsLaunched()
   thenIShouldSeeGreetButton()

}

func testUserShouldGetWelcomeMessageOnceEntered() {
   givenTheAppIsLaunched()
   whenITapGreetButton()
   thenIShouldSeeWelcomeMessage()
}


Now that, we have our GWT are ready but our test target will still not compile as we have to implement these steps. As discussed earlier, we will be using  Swift Extensions to implement step definitions. It’s a good time to make use of them to implement steps as an extension to the Greetable protocol. Let’s create a  Greeter+Extension.swift  file to add the extension to the Greetable protocol with empty methods for GWT like this:

import XCTest

extension Greetable {

    func givenTheAppLaunched() {

    }

    func thenIShouldSeeGreetButton() {

    }

    func whenIPressGreetButton() {

    }

    func thenIShouldSeeWeocomeMessage() {

    }

}


Use XCUI API to Drive Behaviour From GWT

At this stage, our target should compile but it’s not doing anything at the moment. We will drive the behavior for the first scenario using  XCUITest API to launch the app and check if the button exists. The sample code for these will look like this:


func givenTheAppLaunched() {
   XCUIApplication().launch()
}

func thenIShouldSeeGreetButton() {
   XCTAssertTrue(XCUIApplication().buttons["Greet"].exists)
}


Let’s try to execute the test  testHomeScreenHasGreetButton()  from the Xcode Test navigator. We will see that first step for launching an app will pass but the second one for the Greet button will fail. It’s true because a button with accessibility identifier ‘Greet’ doesn’t exist yet.

Implement The Behaviour to Make Steps Pass

Let’s implement a button in the app in order to make this test pass. Follow the steps below:

  • In the  Main.Storyboard , drag a button, and add accessibility identifier as 'Greet.'
  • Click on the Assistance Editor to bring the  ViewController.swift .
  • From the storyboard, select the button and press CTL + Drag it to view controller class.
  • Select ‘Action’ as connection and name the function as ‘GreetUser.’

Now we have a button on the home screen with accessibility identifier ‘Greet,’ which isn’t doing anything, but our first scenario checks existence of the button. Let’s  run the first scenario from Xcode and watch that the test is passing!

Congratulations ! You have implemented your first scenario using protocol-oriented BDD approach. Let’s carry on and implement another scenario too.

In the second scenario, we have to tap the button, and once button is tapped, the user should see the message ‘Welcome to POP.’ In our extension, there is a tep to tap the button and display the message. Add the following code to this step:


func whenITapGreetButton() {
   XCUIApplication().buttons["Greet"].tap()
}


func whenITapGreetButton() {
   XCUIApplication().buttons["Greet"].tap()
}

func thenIShouldSeeWelcomeMessage() {
   XCTAssertTrue(XCUIApplication().staticTexts["Welcome to POP"].exists)
}


Now try to execute the second scenario; you will observe that first step will pass as we have a button with accessibility identifier ‘Greet.’ It will tap on the button and look for the message text ‘Welcome to POP’ but it will fail. It’s true because we haven’t implemented that welcome message yet.

In order to make the second scenario pass, we have to implement the welcome message. Follow these steps to do that:

  • In the  Main.Storyboard  add the label.
  • Bring up view controller using Assistance Editor.
  • CTL + drag the label to View Controller, selection connection as Outlet and name it as WelcomeText.

Now that we have our label in place, we have to tell the button that when button is pressed then label should change to text ‘Welcome to POP.’ Add the following code the function associated with the button:

@IBOutlet weak var welcomeText: UILabel!
@IBAction func greetUser(_ sender: Any) {

  welcomeText.text = "Welcome to POP"

}


That’s it! Now execute the second scenario from Xcode and you will see it’s passing.

Watch it in action:

This tutorial will be continued in Part 2, coming soon.

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:
behavior driven development ,swift ,extensions ,mobile ,ios ,mobile apps ,app development

Published at DZone with permission of Shashikant Jagtap, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}