All posts by Mindful tester

Fast Forwarding Act

Kent Beck used an old programming technique. This way he rediscovered Test Driven Development.

Decades later I was combining Test Driven Development with test automation. According to me it was feasible.
Like the British would say:
“The proof is in the program.”

Recap

In order to make this test automation code work I used Arrange Act Assert.

  • First I had to Arrange, that given my Selenium web driver is in the Form Authentication of https://the-internet.herokuapp.com/.
  • I had to Act: when my Selenium web driver will enter the user name and password, and pressing the Enter button.
  • I had to Assert: then I got a message that I had entered the right credentials.

I had finished Arrange and Assert. The next step was to get Act in place.

Inserting Act between Arrange and Assert

Now I had made code for a situation with no credentials. I had not entered any user name and password, so I did not get access. This seems fair enough.

I programmed my steps using Red Green Refactor, which are used in Test Driven Development.
Under the rectangle Arrange there are two groups of a arrow pointing to the right and three rectangles Red, Gree, and Refactor. The left group is higher than the right group!

Ready Set Code.

Do You Want To Make Some Test Code?
[On the melody of “Do You Want to Build a Snowman?”]

My first step for Act was to enter the user name.

Red:
the failing test was that no user name was entered. I could see, that the user name field was empty.

Green:
I added code in the test code.

loginPage.setUsername("tomsmith");

and additional code for setUsername.

public class LoginPage {

  private WebDriver driver;
  // NB: edited for readbility
  private By usernameField = By.id("username");  

  public void setUsername(String username){
    driver.findElement(usernameField).sendKeys(username);
  }
}

I executed the code. The user name field contained “tomsmith”, so I passed my test.

Refactor:
clean up code was not needed.

My second step for Act was to enter the password. Another round of Red Green Refactor was needed.

Red:
the failing test was that no password was entered. I could see, that the password field was empty.

Green:
I added code in the test code.

loginPage.setPassword("SuperSecretPassword!");

Then I put in additional code for setPassword in the LoginPage class:

public class LoginPage {

  private WebDriver driver;
  private By usernameField = By.id("username");
  private By passwordField = By.id("password");
  private By loginButton = By.cssSelector("#login button");

  public LoginPage(WebDriver driver){
    this.driver = driver;
  }

  public void setUsername(String username){
    driver.findElement(usernameField).sendKeys(username);
  }

  public void setPassword(String password){
    driver.findElement(passwordField).sendKeys(password);
  }

  public SecureAreaPage clickLoginButton(){
    driver.findElement(loginButton).click();
    return new SecureAreaPage(driver);
  }
}

When I used the test code, the password field was filled. I made enough code to pass my failing test.

This piece of code had another effect: a green mark was shown in my programming tool. My Assert was also right: my Selenium web driver was successfully logged in.

I also most had my Act together. One more step.

Refactor:
clean up code was not really needed. Maybe I could have deleted the empty line.

The complete code looked like this:

@Test
public void testSuccessfulLogin(){
  LoginPage loginPage = homePage.clickFormAuthentication();
  loginPage.setUsername("tomsmith");
  loginPage.setPassword("SuperSeretPassword!");
  SecureAreaPage secureAreaPage =
    loginPage.clickLoginButton();
  assertTrue(secureAreaPage.getAlertText()
             .contains("You logged into a secure area!"),
             "Alert text is incorrect");
}

Let Me Code.
[On the melody of “Let It Go”]

Automatic please

There are people who would suggest to automatically check every step in Arrange. Of course this is possible. Here is another piece of code:

public class UploadTests extends BaseTests {
  @Test
  public void testUploadFile(){
    // Arrange
    FileUploadPage fileUploadPage =
      homePage.clickFileUploadPage();

    // Act
    // Upload file
    fileUploadPage.selectFileToBeUploaded(
      "D:\\Users\\Han Toan\\Downloads\\test.txt");
    FileUploadPage.FileUploadedPage fileUploadedPage =
       fileUploadPage.triggerUpload();

    // check header.
    // var result = "ran349454lk";
    var result = fileUploadedPage.getHeader();
    Assert.assertEquals(result, "File Uploaded!", 
      "Wrong page is shown");

    // Assert
    // Check file name
    // result = "ran3495840";
    result = fileUploadedPage.getUploadedFiles();
    Assert.assertEquals(result, "test.txt", 
      "Wrong file uploaded");
  }
}

So the Test in Test Driven Development can be performed on view or automatically.

Overview of TDD in Test Automation

At a low level I have small building steps: Red Green Refactor.
These steps orginated from TDD or Test Driven Development.

Red:
make a failing test.

  • What is the failing test in this particular case? Which text or information is shown to the tester?
  • Does the test provide useful information? Is the message specific enough? “Fail” is not an option, “Wrong screen” is a better one.
  • How do I determine whether the test fail? With my own eyes or automatically?

Green:
make enough code to pass the failing test.

  • Does the test pass?
  • Did I write minimal code to pass this failing test? Did I not add too much in the code
  • Does the code test the application and not my test code?

Refactor:
cleanup the code.

  • Did I take time to look at the code?
  • Do I know the right design pattern to optimise the code? E.g. POM, Page Object Model.
  • Does my programming tool offer options to refactor code? E.g. options in Refactor menu.
  • Do I know a resource, where I can find design patterns? E.g. Test Automation University, “Design Patterns” by Martin Fowler
  • Can I delete redundant automatic tests?
  • Did I execute the refactored code?

At a high level there are three construction phases for automatic tests:

  • Arrange: make sure, that everything is in order before a function is tested in a specific situation.
  • Act: perform the function to be tested.
  • Assert: determine, whether the tested function can be used in the right way in this specific situation.

For a construction phase I could use one or more cycles of building steps: Red, Green, and Refactor.

Most of the time I use them in a chronological order. I start at the beginning of Arrange and work slowly to the end of Arrange. It is the same with Act.

here are two groups of a arrow pointing to the right and three rectangles Red, Gree, and Refactor. The left group is higher than the right group!

For Assert I change the order, because Assert works as expected in a specific situation. In this case I start at the end and work my way back to the beginning.

There are two groups of a arrow pointing to the right and three rectangles Red, Gree, and Refactor. The left group is lower than the right group!

My whole approach for TDD in Test Automation can be summarised as follows:

Arrange followed by an arrow pointing to the right Assert followed by an arrow pointing to the left Act followed by an arrow pointing to the right!

The main reason to make an Assert before the Act is to assure that my Assert can provide me information about the wrong situation. More information can be found in my previous blog post.

FAQ or Frequently Asked Questions

Here are some questions, which I asked myself after several sessions of deliberate practice. Some of my answers are based on practice. Other answers are theoretical, which have to be tested in practice.

I ‘m a tester after all.
[On the melody of “It’s a small world after all.”]

Q: If I have a form with 9 fields, do I have to check whether Selenium Webdriver has entered the right values?
A: Some reasons for checking the contents of the fields are a change of the user interface and screen flow by filling the key fields properly. Examples are extra entry fields popping up or warnings about format shown to the user.

Q: Are there reasons to skip the checking of all 9 fields?
A: If the user interface will not change much. Another reason is that you do not want to test the Selenium code. A third reason is time saving.

Q: Is there an alternative for an automated check of field entry?
A: Yes, I can view changes with my own eyes. Or demonstrate my code to someone else.

Q: You use Arrange, Act, and Assert. You could also use Given, When, and Then. Why do you prefer the first ones?
A: I expected the question. For the people unfamiliar with this construction I edited the first section

  • Given I am in the Form Authentication of https://the-internet.herokuapp.com
  • When I enter a valid user name and password combination
  • Then I get a message that I had entered the right credentials
    The description of the steps are at a higher level than the steps in the first section, but it basically leads to the same result. The reason I use Arrange, Act, and Assert is to put myself in action. I have code to write and it will not write it self.

Q: You mentioned time saving. Why would it save time to skip tests?
A: If I give directions for a walk in Amsterdam, it is along the lines:
“First street right, 3rd street left, etc.”

I do not tell:
“You see a house with number 12. Continue walking to the red brick house with number 34, then turn to the right. At your right you see a small house with number 45b. Continue walking to the brick house with number 85a, then turn to the left.”
This costs a lot of time to tell and to remember. You can give it a try.

End of example

Let me write a little more about the directions to walk from the Rijksmuseum to the Palace in Amsterdam.
The Palace is situated on a dam. The Dam – yes seriously – is a place with buildings around it.

My next instructions would be like:
Go to the Monument on The Dam. This looks like a big needle with a sculpture at the bottom.
Look over The Dam with your back to the Monument on The Dam.
Then you can see the royal palace.

Of course readers might object:
“How are you sure you are looking at the right building?”
In my previous blog post I wrote, how the tourist could Assert this:
it look like a grey huge townhall with a dome.

For the people with normal vision there is no white castle with rank towers.
For the people with X-ray vision there is no Sleeping Beauty in the palace.

Last quote

Why should I not practice TDD in test automation?
It is a weird idea. Like TDD.

“No one is stupid enough to be a competitor. For about a year.”
Kent Beck about Explore at YOW! Conference 2018.

Fast Forwarding Assert

Recap

In order to make this test automation code I used Arrange Act Assert.

  • First I had to Arrange, that given my Selenium web driver is in the Form Authentication of https://the-internet.herokuapp.com/.
  • I had to Act: when my Selenium web driver will enter the user name and password, and pressing the Enter button.
  • I had to Assert: then I got a message that I had entered the right credentials.

I had finished Arrange. The next step was to add Assert. I know that this seems a bit of order, but you are allowed to read the section “Trust”. It would be great that you would return for the technical stuff in the next section.

Connecting Arrange and Assert

My first attempt to make Assert was a failure. It was code which tested my code instead of the code under test.

Now I needed to look again to the Red Green Refactor cycle of Test Driven Development or TDD in Assert.
In the upper part there is a rectangle "Assert". Under this rectangle there are two groups rectangles "Red", "Green", "Refactor". The left group is lower than the right group!

What was Assert supposed to do?
It was supposed to show some message. I had to translate Assert to Red Green Refactor.

  • Red: no message is shown.
  • Green: a message is shown.
  • Refactor: cleanup code.

If it was too difficult for one cycle, I could always use additional Red Green Refactor cycles.

The first step is Red or make a failing test. How did I determine whether the message was not shown?
I looked with my own eyes. Guess what? I had already a failing test.

The second step is Green or make enough code to pass the failing test,
It was time for my rebound. I had enough code in Arrange to make useful code for Assert.

 
   assertTrue(secureAreaPage.getAlertText()
              .contains("You logged into a secure area!"),
              "Alert text is incorrect");

I could plug in my code like this:

@Test
public void testSuccessfulLogin(){
  LoginPage loginPage = homePage.clickFormAuthentication();
  assertTrue(secureAreaPage.getAlertText()
             .contains("You logged into a secure area!"),
             "Alert text is incorrect");
}

But this would lead to code, which could not be compiled. For starters secureAreaPage was not initialised and did not have a method getAlertText. Code which is not executable can not be tested. The line with assertTrue was unusable.

The test could not be performed, so it is not really a proper Assert.

Now I had to introduce a secureAreaPage.

public class LoginPage {

  private WebDriver driver;
  private By loginButton = By.cssSelector("#login button");

  public LoginPage(WebDriver driver){
    this.driver = driver;
  }

  public SecureAreaPage clickLoginButton(){
    driver.findElement(loginButton).click();
    return new SecureAreaPage(driver);
  }
}

Painful discoveries

While blogging my code looked perfect to me, but my memory was not that perfect. When I coded, I did not use version control system for my personal project at that moment. Luckily I had made short notes in charters. I missed some notes, but I was still able to reconstruct my steps.

Another thing I noticed was, that the code for testBackspacePressed was written before testSuccessfulLogin. I could change flash forward to flash backward. But that would be quite confusing for the reader. So this blog post serie is based on real stories.

Connecting Assert and Act Continued

A way to introduce secureAreaPage in the code is to insert a new line of code:
“SecureAreaPage secureAreaPage = loginPage.clickLoginButton();”

@Test
public void testSuccessfulLogin(){
  LoginPage loginPage = homePage.clickFormAuthentication();
  loginPage.setUsername("tomsmith");
  loginPage.setPassword("SuperSecretPassword!");
  SecureAreaPage secureAreaPage = loginPage.clickLoginButton();
  assertTrue(secureAreaPage.getAlertText()
             .contains("You logged into a secure area!"),
             "Alert text is incorrect");
}

Now secureAreaPage was initialised, but now I had to code a method clickLoginButton.

public SecureAreaPage clickLoginButton(){
  driver.findElement(loginButton).click();
  return new SecureAreaPage(driver);
}

There was still something missing. I missed a class for SecureAreaPage. So I coded a class with a constructor SecureAreaPage and the long awaited method getAlertText. For the newbie programmers a constructor is a method to make object. If there is no constructor, then there is no object to manipulate or test.

public class SecureAreaPage {
  private WebDriver driver;
  private By statusAlert = By.id("flash");

  public SecureAreaPage(WebDriver driver){
    this.driver = driver;
  }

  public String getAlertText(){
    return "ran394594";
  }
}

Notice, that I put in some random text in the method getAlertText. So every time getAlertText is invoked, it will return “ran394594”.

Now comes the interesting part. Let us have a look what happens, if the following line is executed:

assertTrue(secureAreaPage.getAlertText()
             .contains("You logged into a secure area!"),
             "Alert text is incorrect");

secureAreaPage.getAlertText() returns “ran394594”.
This is different from “You logged into a secure area!”,
so the following error message was shown to me:
“Alert text is incorrect”.

So I had finished Green: a message is shown.

The third step of the cycle in TDD is Refactor. The code was already well structured. End of cycle.

Time for a flash forward for another example

@Test
public void testBackspacePressed(){
  // Arrange
  // String header  = "Random text";
  var keyPressesPage = homePage.clickKeyPresses();

  String header  = keyPressesPage.getHeader();
  Assert.assertEquals(header, "Key Presses", "You entered the wrong page.");

  // Assert
  String result = keyPressesPage.getResult();
  Assert.assertEquals(result, "You entered: BACK_SPACE", "Wrong key detected");
}

Stumbling around

Some readers might prefer a straight forward description of TDD in test automation. And yes, I will describe it more concisely in the next blog post. My message is that it took time to adjust my mind to a new way of developing. I had to unlearn things. That is difficult.

Let me clarify this a bit more. Test Driven Development in test automation sounds like programming and testing of programming and testing. It took me a lot of effort to keep the Arrange, Act, and Assert apart from the Red, Green, and Refactor.

Another thing is that blogging this way gives me a better understanding how it works. It is no theory; it is real practice; it does actually work.

Trust

“Never trust a test you have never seen fail.”

I have seen talks of Angie Jones and Bas Dijkstra, two good test automation experts. Their recurring warning is always to see whether the test actually worked. They used Arrange, Act, and Assert in this order. Then they changed Act to see whether the Assert would show an error.

By using the order Arrange, Assert, and Act I know that Assert is testing the right thing. If I will finish my Act in the next blog post, I do not have to change Act to verify my Assert.

A small story to end this blog post

Maybe you remember the story about the walk from the Rijksmuseum to the palace in Amsterdam from the previous blog post. It is not some palace, but a real royal palace is used by the Dutch king and queen.

Lots of kids would go like
“Awwww, white castle with rank towers.
We want to see it!
Now!
Please.”

Only the royal palace is different from the one from a fairy tale. If you are on The Dam, there is no single building looking like that castle of a Sleeping Beauty.

How do I describe this palace to a tourist?
It looks like a grey huge townhall with a dome. This is a way to assert that a tourist is looking to the right building.
Sorry kids for spoiling the fun.

My next blog post is about inserting Act between Arrange and Assert.

Fast Forwarding Arrange

At that moment I had a test, which would always pass. This was not the right starting point.

Putting

The first phase of a test is to arrange, that things can be tested. Somehow I had to land on the Login Page on https://the-internet.herokuapp.com/. In other words put the automation tool on the same page. And off I coded.

What is a way to identify this screen?
Okay, the header is “Login Page”.
Now I can use Red, Green, and Refactor to make the final step to this screen.

Red or making a failing test was simple, because nothing could be seen.

@Test
public void testSuccessfulLogin(){
  assertTrue(loginPage.getHeader()
               .contains("Login page"),
               "You entered the wrong page.");
}

Green: now I had to make enough code to pass the test. The code was quite simple.
In LoginPage.java I made a method for the class LoginPage:

public String getHeader(){
  return "ran394594";
}

Refactor: the code looked simple. So there was no need for cleanup.

There was a drawback. I had a continuous passing test. This reminded me of the last unsuccessful attempt. In that case I started with a failing test of the Assert. Also in this case I ended with test code unconnected with the code under test.

Things

Then I realised that I had repeated the same wrong steps. This walk was clumsy. I started at the end of the Arrange and wanted to walk back with Red, Green, and Refactor.

In the upper part there is a rectangle "Arrange". Under this rectangle there are two groups rectangles "Red", "Green", and "Refactor" under an arrow pointing to the left. The left group is lower than the right group!

A lot of people state that you should start with the desination and then try to figure out what you need to get there. I had the feeling that I was rather awkward.

Let us assume that I have to provide some information to a wondering visitor of The Netherlands.
Imagine me walking backwards from the Palace on the Dam to the Rijksmuseum in Amsterdam.
They might mistake me for being a tourist. I hope.
Better to take some extra pictures. A habit of tourist. I think.

In the right order

It was better to start with Red, Green, and Refactor at the beginning of the Arrange. And from there I would slowly walk in the right direction.
Under the rectangle Assert there are two arrows RGR pointing to the right. The left RGR is higher than the right RGR!

So I needed to have code to get to the home page. But LoginPage.java extends BaseTests.java. This basically means that all code in BaseTests.java also applies to LoginPage. I discovered that the code to get to the Home Page was already present.

@BeforeClass
public void setUp(){
  System.setProperty("webdriver.chrome.driver", "resources/chromedriver.exe");
  driver = new ChromeDriver();
  driver.get("https://the-internet.herokuapp.com/");

  homePage = new HomePage(driver);
}

My first step was to put the code with getHeader in a comment.

@Test
public void testSuccessfulLogin(){
  /*
  assertTrue(loginPage.getHeader()
               .contains("Login page"),
               "You entered the wrong page.");
  */		   
}

Red: now I had to test that the Login Page was not shown. There was no code in place, so my test would always fail. I checked with my own eyes, that the Login dialog was not shown

Green: then I made some code to get there

@Test
public void testSuccessfulLogin(){
  /*
  assertTrue(loginPage.getHeader()
               .contains("Login page"),
               "You entered the wrong page.");
  */
  LoginPage loginPage = homePage.clickFormAuthentication();
}

I also needed some code for the method clickFormAuthentication in HomePage.java.

private By formAuthenticationLink = By.linkText("Form Authentication");

public LoginPage clickFormAuthentication(){
  driver.findElement(formAuthenticationLink).click();
  return new LoginPage(driver);
}

I executed the code again. And I saw the Login dialog.

Refactor: the code contained some comment with old code.

@Test
public void testSuccessfulLogin(){
  /*
  assertTrue(loginPage.getHeader()
               .contains("Login page"),
               "You entered the wrong page.");
  */
  LoginPage loginPage = homePage.clickFormAuthentication();
}

I deleted the comment:

@Test
public void testSuccessfulLogin(){
  LoginPage loginPage = homePage.clickFormAuthentication();
}

Also I noticed, that there were only manual checks and no automatic tests in the code of login page. Somehow I let my attention slip away. Again.

It is time for a flash forward. A few practice runs later:

@Test
public void testBackspacePressed(){
  // Arrange
  // String header  = "Random text";
  var keyPressesPage = homePage.clickKeyPresses();

  String header  = keyPressesPage.getHeader();
  Assert.assertEquals(header, "Key Presses", "You entered the wrong page.");
}

Why should I bother to use Red, Green, and Refactor so intensively?
This was the only way for me to fully experience this new way of developing. Later on I could always change things.

Okay, back to the point where I was trying to test a login form.
There I was. Ready to make actual tests.

This exercise was so small, that I started at the wrong point twice.

  1. At the end of the Assert
  2. At the end of the Arrange.

The whole way of programming in the right direction was still not a natural thing for me.

Somehow I forgot the time being a test coordinator for performance tests. My team members had to make scripts for complete unknown websites. My task was to simplify this by asking for click paths.
“Would you please provide screenshots, which are shown to to the user, and the input of the users?”

Another side note

In music there is a saying that the tape does not lie. If you are a good musician, then the recording will prove it. For software development I could translate it to “the code does not lie”. For doubtful people I could change it to the “the version control system does not lie”.

I could write about an error free test automation experience, which is not real.
My coding in TDD in test automation was still in progress. I was learning.

My next blog post is about fixing the Assert.