July 6, 2015

The-Internet: Storing constants: static final vs enums

Testing The-Internet:

Rewriting the automated test code we use at work to test against Dave Haeffner's mock site, The-Internet: Login Page.

This post is third in a series of six. Need to go back to the beginning?


Part Three: Storing Constants 

Setting Constants Using Static Final

When using values such as the username and password of a Login screen hardcoding values within your automated test is a bad idea. 

If there was an automated test that was to go to https://the-internet.herokuapp.com/login and enter the username and password for Tom Smith (tomsmith / SuperSecretPassword!).


WebElement txtUsername = driver.findElement(By.id("username"));
System.out.println("Entering username...");
txtUsername.sendKeys("tomsmith"); 
WebElement txtPassword = driver.findElement(By.id("password"));
System.out.println("Entering password...");
txtPassword.sendKeys("SuperSecretPassword!");
What if the username or password changes? How can you easily find the users that need to be updated? 

With the username and password embedded in the test, the test is not easily maintainable. 

Before these enumerated data types were introduced into Java 1.5, we could only have declared them as public static final: 

Let's examine parts of the code I wrote in my initial quick and dirty test of Dave Haeffner's site in https://github.com/tjmaher/WebDriver_TheInternet_Basics/blob/master/src/test/java/SimpleManipulationWebElements.java:

private static final String USERNAME = "tomsmith";private static final String PASSWORD = "SuperSecretPassword!";
...
...
txtUsername.sendKeys(username); // enters the username into the textbox
txtPassword.sendKeys(password); // enters the password into the textbox

The Java keywords static and final are how you declare constants. 

About the keyword static
"Sometimes, you want to have variables that are common to all objects. This is accomplished with the static modifier. Fields that have the static modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class". - The Java Tutorials: Classes and Objects
About the keyword final:
"The static modifier, in combination with the final modifier, is also used to define constants. The final modifier indicates that the value of this field cannot change. 
"For example, the following variable declaration defines a constant named PI, whose value is an approximation of pi (the ratio of the circumference of a circle to its diameter): 
"static final double PI = 3.141592653589793; 
"Constants defined in this way cannot be reassigned, and it is a compile-time error if your program tries to do so. By convention, the names of constant values are spelled in uppercase letters. If the name is composed of more than one word, the words are separated by an underscore (_)".- The Java Tutorials: Classes and Objects

Setting Constants using Enums

Another solution is to store these USERNAME and PASSWORD values as Enums

"An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week. 
"Because they are constants, the names of an enum type's fields are in uppercase letters.In the Java programming language, you define an enum type by using the enum keyword [...]
"You should use enum types any time you need to represent a fixed set of constants. That includes natural enum types such as the planets in our solar system and data sets where you know all possible values at compile time—for example, the choices on a menu, command line flags, and so on. -- Enum Types, The Java Tutorials, Oracle.com. 

These variable strings USERNAME and PASSWORD are global constants. They can only have the preceding values that we have set, cannot be accidentally overwritten, wherever they are used. 

What are some of the problems of using public static final

"public static final int SEASON_WINTER = 0;
public static final int SEASON_SPRING = 1;
public static final int SEASON_SUMMER = 2;
public static final int SEASON_FALL   = 3;
This pattern has many problems, such as:
  • "Not typesafe - Since a season is just an int you can pass in any other int value where a season is required, or add two seasons together (which makes no sense).
  • "No namespace - You must prefix constants of an int enum with a string (in this case SEASON_) to avoid collisions with other int enum types.
  • "Brittleness - Because int enums are compile-time constants, they are compiled into clients that use them. If a new constant is added between two existing constants or the order is changed, clients must be recompiled. If they are not, they will still run, but their behavior will be undefined.
  • "Printed values are uninformative - Because they are just ints, if you print one out all you get is [text], which tells you nothing about what it represents, or even what type it is.
[...] "So when should you use enums? Any time you need a fixed set of constants. That includes natural enumerated types (like the planets, days of the week, and suits in a card deck) as well as other sets where you know all possible values at compile time, such as choices on a menu, rounding modes, command line flags, and the like."  
In the Seasons example above, they mention that using enums, it could look like:

"enum Season { WINTER, SPRING, SUMMER, FALL }"

Using Enums to Store Usernames and Passwords

By using enums, we can group a test user's login credentials, both username and password. Here is an example I wrote based on what we are currently using at work at the time:

public enum UserEnum {

    TOM_SMITH("tomsmith","SuperSecretPassword!");

    String userName;
    String password;

    private UserEnum(String UserName, String Password){
        this.userName=UserName;
        this.password=Password;
    }

    public String getUserName(){
        return userName;
    }

    public String getPassword(){
        return password;
    }
} // From my code: test/java/tests/LoginTest.java.


Please note: Storing usernames and passwords as a UserEnum is a bad idea. It is better to store them in a properties file, where they can be more secure. I am just using them here to illustrate a simple example of using an Enum with The-Internet.

To access the username and password for user TOM SMITH, we could just call:








  • TOM_SMITH.getUserName();
  • TOM_SMITH.getPassword();
  • If we wanted to pass all the user information for TOM SMITH to a method that logs the user in by passing in the entire enum:

    logIntoPage(TOM_SMITH);

    The method create to handle logging in users, such as with WebDriver_TheInternet_Advanced: test/java/pages/LoginPage.java, can then extract the information from the enum itself. 

        public void logIntoPage(UserEnum user){

            String username = user.getUserName();
            String password = user.getPassword();

            enterUserName(username);
            enterPassword(password);
             
            // Click the login button
        }

    For my next blog post, I will cover how we currently use enums for locators at my workplace.

    NEXT: Storing locators in enums



    -T.J. Maher
     Sr. QA Engineer, Fitbit
     Boston, MA

    // Automated tester for [ 4 ] month and counting!

    Please note: 'Adventures in Automation' is a personal blog about automated testing. It is not an official blog of Fitbit.com
    Post a Comment