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.
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.
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.
My whole approach for TDD in Test Automation can be summarised as follows:
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.