DRY or Don’t Repeat Yourself – part 2

One evening I had a wrap on my plate. Then I took a modest amount of vegetarian filling. My wife noticed this:
“No wonder you can eat three wraps.”

Refactoring

My wife improved my meal with this single remark. The more filling, the better. Lucky for me, she did it, before I would eat my wrap. These small things add up.

In software development improving the code is called refactoring. The first step is to notice something wrong, which is followed by using the right solution.

Let’s go back to the wraps. My wife saw, that I did not put enough filling on my wrap. Then her solution was more filling.

Refactoring in practice

After hours of programming, I had a test scenario for the Cinema VIP app, where the number of Colas was increased because of the Desert scene in Monsters Unlimited.

Some steps from the scenario were:

  • order 1 Cola in the Drink and Snack page,
  • go to the next page,
  • regret my choice, (I did not code this, but it adds to the flavor.)
  • go back to the Drink and Snack page,
  • change the number of Colas to 2 in the Drink and Snack page, and
  • go to the next page.

Changing lines

A note for the screen reader users: characters like parentheses, dot, and braces are used in the code. It is advised to change the interpunction and symbol level before reading the code.

Then it was time for me to have a close look to the code. The line of code to find the text field with the number of Colas was used twice. First I set it to 2 and later to 1. Every time the Snack and Drink page was opened, the text field must be found again.

In my code I found the following line twice.

WebElement numberOfColasTextfieldSnackAndDrinkPage = 
  driver.findElement(
    By.name(“4958495”);

This means: find the text field with the name 4958495.

I had to change this, so I added the following line:

public static final String NUMBER_OF_COLAS_TEXT_FIELD =
  “4958495”;

This means: NUMBER_OF_COLAS_TEXT_FIELD is 4958495.

Then I changed both lines to find the text field.

WebElement numberOfColasTextfieldSnackAndDrinkPage = 
  driver.findElement(
    By.name(NUMBER_OF_COLAS_TEXT_FIELD);

This means: find the text field with the name NUMBER_OF_COLAS_TEXT_FIELD.

I had severe doubts about NUMBER_OF_COLAS_TEXT_FIELD. In my test scenario several windows were used. There was only 1 Number of Colas Text Field in the whole application. On the other hand every page had an OK button. Using OK_BUTTON is an accident to happen.

So I changed OK_BUTTON in the Drink and Snack Page to OK_BUTTON_DRINK_AND_SNACK_PAGE. So I used
NUMBER_OF_COLAS_TEXT_FIELD_DRINK_AND_SNACK_PAGE.

In this case I used refactoring to make sure, that my test automation would still work. I like code which is easy to read and change.

Time for some reflection

I noticed the recurring lines of code. This would lead to code which would be difficult to maintain. I remembered DRY or Don’t Repeat Yourself.

My solution was to use a single line of code to determine the name of the Number of Colas Text Field. If the name would change, then I had only to change this line of code.

Page Object Model

A few weeks later I had 3 scenarios with the Drink and Snack Page containing the same lines:

numberOfColasTextfieldSnackAndDrinkPage.sendKeys("1");
numberOfPotatoChipsfieldSnackAndDrinkPage.sendKeys("1");
oKButtonDrinkAndSnackPage.click();

This means:

  • order 1 Cola
  • order 1 potato chips
  • press the OK button.

These same lines of code in 3 different test scenarios did not feel quite right to me. Repeat after me: Don’t Repeat Yourself. There was still too much repetition.

I already used objects for the web elements. Then a tester introduced me to the Page Object Model. I looked at her code and saw less lines of code to do similar things.
“Why did you tell me this before?”
“First you have to get comfortable with the normal way of coding.”
She got a point.

The Page Object Model or POM makes objects for complete pages. So the Drink and Snack page was an object.

My test scenario contained the following actions:

  • select the movie in the Movie Page.
  • select the drink and snack in the Drink and Snack Page.
  • confirm the made options in the Confirm Order Page.

The first 2 steps I programmed as follows:

MoviePage moviePage = homepage.selectMovie();
DrinkAndSnackPage drinkAndSnackPage =
  moviePage.confirmMovie("Monsters Unlimited");
ConfirmOrderPage confirmOrderPage = 
  drinkAndSnackPage.selectColaAndPotatoChips();

This code was more readable than all those detailed lines of code. This also saved me a lot of space.

I put all the code for the web elements of the Drink and Snack Page in the following method:

public ConfirmOrderPage selectColaAndPotatoChips();
{ 
  WebElement numberOfColasTextfield = 
    driver.findElement(
      By.name(NUMBER_OF_COLA_TEXT_FIELD);
  WebElement numberOfPotatoChipsTextfield = 
    driver.findElement(
      By.name(NUMBER_OF_POTATO_CHIPS_TEXT_FIELD);
  WebElement okButton = 
    driver.findElement(
      By.name(OK_BUTTON);
  
  numberOfColasTextfieldSnackAndDrinkPage.sendKeys("1");
  numberOfPotatoChipsfieldSnackAndDrinkPage.sendKeys("1");
  oKButtonDrinkAndSnackPage.click();
  
  return ConfirmOrderPage(driver);
}

In the meantime I could not resist another refactoring. I put all the code for the Snack and Drink Page in one Java file. So all mentioned web elements in this file are on this page. So I renamed NUMBER_OF_COLAS_TEXT_FIELD_DRINK_AND_SNACK_PAGE to
NUMBER_OF_COLA_TEXT_FIELD.

Cliffhanger coming up

At the end I used DRY or Don’t Repeat Yourself. Less copied lines meant less problems. It was time to hit the wall again.

To be continued.