Using Default Test Data

For automated tests

Posted by Nick Oppersdorff on May 7, 2017 0 Comments

Why use default test data?

Imagine a really long online registration form requiring a user to navigate through multiple pages, entering data as they go. Suppose we wanted to test some functionality several pages into the journey. It is highly likely that we don't really care about the data we enter on earlier pages in the journey, we just want it to get to the page under test. As such, why waste time crafting this data for each specific test if we don't care about it?

By creating default data, we are able to simplify our test creation, using the defaults for the stuff we don't care about and overriding the data specific to the test in question.

Git Repository

A git repository is available containing all the examples used in this blog post: here

Encapsulating Test Data with Groovy Beans

A simple solution to avoid specifying new data for each test is to encapsulate data in Groovy beans (or Java beans!), pre populating the bean properties with default data.

For the purposes of this example, think of a "bean" as a class containing pre-populated properties accessed via getters and setters.

Example data entity

It is always good to define data in terms of the business entities involved in the test. Lets assume we are testing a Login page. We would typically have Username and Password fields. We might consider the data for these fields as belonging to a User. A simple data entity might be a User that we model with User.groovy.

      package dataentities

class User {
    def username = "testUser"
    def password = "abc123"
    def firstname = "Tester"
    def surname = "TestSurname"
    def email = "testuser@test.com"
}
  

Writing Automated Tests that use Data Entities

Now we have created our test data, we want to use it to do some testing! Lets write some tests for a Login page that demonstrate how we can read and override the default data. Note that the examples below will compile but won't run.

Example test that reads the default data

Lets look at a test that verifies a successful login in LoginPageSpec.groovy.

      def "User is able to log in with valid username and password"() {
        given: "A user"
        User userDetails = new User()

        and: "The user is on the Login page"
        to LoginPage

        when: "The user enters their login credentials"
        enterLoginDetails(userDetails)

        and: "Submits their credentials"
        submitCredentials()

        then: "The user is successfully logged in"
        title == "Welcome $userDetails.firstname $userDetails.surname"
    }
  

Example test that overrides the default data

Lets look at a test that overrides the default password in LoginPageSpec.groovy.

      def "User is unable to log in without specifying a password"() {
        given: "A user with no password specified"
        User userDetails = new User()
        userDetails.with {
            password = ""
        }

        and: "The user is on the Login page"
        to LoginPage

        when: "The user enters their login credentials"
        enterLoginDetails(userDetails)

        and: "Submits their credentials"
        submitCredentials()

        then: "The user is not logged in"
        title == "Login failed!"
    }
  

Example Login page object

Here is the sample page object, LoginPage.groovy, that is used in the example tests above. It contains a method that makes use of the data entity User.groovy.

      package pages

import dataentities.User
import geb.Page

class LoginPage extends Page {

    static at = {
        title == "Login"
    }

    static content = {
        usernameInput {$()}
        passwordInput {$()}
        loginButton {$()}
    }

    def enterLoginDetails(User userDetails) {
        usernameInput.value(userDetails.username)
        passwordInput.value(userDetails.password)
    }

    def submitCredentials() {
        loginButton.click()
    }
}
  

Why is this a good way of doing things?

Rather than thinking about all the data required for a test, we simply need to focus on the data that is directly relevant to the outcome we are testing and rely on the defaults for other values where appropriate.

We reduce our maintenance by writing our page object methods so that they take data entity objects rather than individual data field values giving us concise, stable method signatures, leaving it to the page object methods in question to read out the values they require, reducing maintenance over the longer term.