Behavior Driven Development with Gondola

Behavior Driven Development

Introduction

A common problem is the lack of clear communication between business and technical teams. While a stakeholder might better understand a use scenario, they may not be able to implement it in code. A programmer can write the code, but might not be sure where to start. A solution to this is Behavior Driver Development (BDD). By thinking in terms of use scenarios instead of test, business teams can have a greater hand in writing test, and technical teams will have a better outline when implementing them. The development is driven by the behavior associated with using the application.

Feature Files

To write our use scenarios, we'll use a feature file. This will ... describe the feature we're testing. For this we'll use something called Gherkin. Gherkin provides a common language that both technical and non-technical teams can understand. In gherkin you'll write a scenario using the Given-When-Then format.

Here's an example feature file:

Feature: Error message
  Background: Email for app
  Given the user is at an email form
  Scenario: Bad Email Address
    When the user enters email "bademailgmail.com"
    Then the user should see  error
  Scenario: Good Email Address
    When the user enters email "[email protected]"
    Then the user should see confirmation

As you can see, someone with no coding background would easily understand this. If it's all Greek to you, don't worry. Gherkin has been translated to over 70 languages. If your team feels more comfortable designing scenarios in another language, it's no problem.

When writing a feature file it's important to note that Every action in a test should not have its own line in a scenario.

  • Wrong
Feature: navigate to webpage and search for images
    Scenario: The user is going to google to search for puppies
        Given the browser is open
        When the user enters "google.com"
        And the user hits enter
        And the user enters "puppies"
        And the user hits enter
        Then the user should see pictures of "puppies"
  • Right
Feature: navigate to a webpage
    Scenario: the user is going to Google.com
        Given the browser is open
        When the user navigates to "google.com"
        Then use user should see "Google"
Feature: image search
    Scenario: the user is image searching for puppies
        Given the user is at "google.com"
        When the user searches for puppies
        Then user should see puppies

Step Definition

To translate the feature file into code, we'll use a step definition file. Here's a code snippet from a step definition file for the above scenario. These function inside the steps are made up for conceptual purposes.

Given("the user is at an {string} form",async (form:string)=>{
if (getFormType()!=form){
 throw new Error("Incorrect form");
}
})
When("the user enters email {string}", async (email:string)=> {
emailform.enterText("email");
});
Then("the user should see {string}",async (messagetype:string)=>{
if (!getPopup().type===messagetype)
{
 throw new Error("Message type does not match");
}
});

Gondola

We're going to use BDD to test the login page of the Car Rental app. Open Gondola Studio and create a new project. Select Android BDD as the project type.

Writing the story

We'll test the login page of the app, so let's write a scenario. When we are at the login page we'll enter a username and password. When we login we should see the homePage. If the username or password are wrong we should see and error message.

  1. Navigate to the src/features folder and create a new file named LoginExample.feature

  2. Enter the following and save the document

Feature: Login Validation
    Background: App is started to Login page
        Given I am at the "loginPage"
    Scenario: Valid login
        When I login by username "john" and password ""
        Then I should see "pageTitle" of "homePage"
    Scenario: Invalid login
        When I login by username "Invalid" and password "Invalid"
        Then I should see "InvalidMsg" of "loginPage"

Writing the Step Definitions

  1. Navigate to the src/step_definitions folder and create a new file name loginStepDef.ts

  2. In the first few lines import the following

import {gondola} from "gondolajs";
import loginPage from "../pages/loginPage";
import { getPageClass } from "../common/utils";

import loginPage ... imports a Page Object which is a object-oriented model of a page. This has the functions and locators required to interact with the login page.

  1. Now let's write our Given function
Given("I am at the {string}", (pageName: string) => {
    const pageClass = getPageClass(pageName);
    if (pageClass){
        const packageId = pageClass.packageId;
        if (packageId){
            gondola.runOnAndroid(async () => {
                await gondola.checkAppIsInstalled(typeof(packageId) === "string" ? 
                    packageId : packageId.android!);
            });
        }
    } else {
        throw new Error("Invalid page was given. Page is not found or corrupted.");
    }
});

This will check if the the page name of the app matches the page in the feature file. If they're not the same, the test will fail.

Now on to the When

When("I login by username {string} and password {string}", async (user: string, pass: string) => {
    await loginPage.login(user, pass);
});

loginPage.login(user,pass) uses a method from a Page Object. This Page Object defines the locators and methods for interacting with the login page. This way you can have many test that interact with the login page, but you'll only need to write the method once. Also, if the login page changes at some point, you'll just need to edit the page object, not all your tests. This tutorial is focused on writing test, so we won't discuss the creation of page objects here, but if you look in src/pages you can see the one we're using for this tutorial.

And for the Then

Then("I should see {string} of {string}", (ele: string, parent: string) => {
    let parentPage;
    if (parent){
        parentPage = getPageClass(parent);
    }
    let toCheck = ele;
    if (parentPage && parentPage.hasOwnProperty(ele)){
        toCheck = parentPage[ele];
    }
    gondola.checkControlExist(toCheck);
});

If it's a valid login, the test checks for the element "pageTitle" of "homePage", if it's invalid it test for the message "invalidMsg" of the "loginPage".

Benefits

This way coders can write write one step definition file and test several things with a feature file (which can be written/edited by non-technical staff). If there's a specific error message for a blank username or password we could add a section to the feature file to test for that with out any additional coding in the step_definition file. Here are a couple of examples.

Scenario: Empty Fields
    When I login by username "" and password ""
    Then I should see "BlankMsg" of "loginPage"
Scenario: Invalid Characters
    When I login by username "@#FJF" and password "^^^ffg]["
    Then I should see "InvalidCharactersMsg" of "loginPage"

Conclusion

A stakeholder with a strong grasp of the product's design and usage can easily write scenarios. A coder can understand what is to be tested in an unambiguous way. Ideally business, development and testing teams will work together to write the feature files. Gondola and Gherkin are a great Android testing combination.

Comments are closed.