When you start automation, you may encounter various methods, technologies, frameworks, and tools that may be included in your automation code. Sometimes, this versatility results in more complex code than providing better flexibility or better ways to solve problems. When writing automated code, it's important that we clearly describe the goal of automated testing and how we can achieve it. That said, it's important to write "clean code" to provide better maintainability and readability. Writing clean code is not easy either, and you need to keep many best practices in mind. The following topics highlight the eight silver lines you should get for writing better automation code.
1. Naming convention
This is really one of the rules of thumb to keep in mind when we move from manual to automation or actually writing code in any programming language. Following the correct naming conventions helps to understand the code and maintenance more easily. This naming convention implies variables, methods, classes, and packages. For example, your method name should be specific to its purpose. “ Register_ The user() "method describes the method in which user registration is displayed. Clearly defined method names add ease of maintenance and readability to scripts. This also applies to variable naming. I've noticed that many people refer to variables as a, b, c, etc., and even call Web elements weblement1, Webelement2, etc. As a result, the user does not see the variable name as expected.
The following is an example of displaying naming errors:
public void Register_User() throws InterruptedException { driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS); driver.get("https://www.lambdatest.com/ "); driver.manage().window().maximize(); WebElement web1= driver.findElement(By.xpath("//a[text()='Free Sign Up']")); web1.click(); WebElement web2=driver.findElement(By.xpath("//input[@name='organization']")); web2.sendKeys("LambdaTest"); WebElement web3=driver.findElement(By.xpath("//input[@name='first_name']")); web3.sendKeys("Test"); WebElement web4=driver.findElement(By.xpath("//input[@name='last_name']")); web4.sendKeys("User"); WebElement web5=driver.findElement(By.xpath("//input[@name='email']")); web5.sendKeys("sadhvi.singh@navyuginfo.com"); WebElement web6=driver.findElement(By.xpath("//input[@name='password']")); web6.sendKeys("TestUser123"); WebElement web7=driver.findElement(By.xpath("//input[@name='phone']")); web7.sendKeys("9412262090"); WebElement web8=driver.findElement(By.xpath("//button[text()='SIGN UP']")); web8.click(); Thread.sleep(3500); }
The above code shows how "method1" does not provide any clues to the user, just as it does for the exact purpose of the method. In addition, all web elements are represented by web1, web2, etc. The user does not recognize which web element captures which field.
For the same code above, you can mark the correct representation as follows:
public void Register_User() throws InterruptedException { driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS); driver.get("https://www.lambdatest.com/ "); driver.manage().window().maximize(); WebElement link= driver.findElement(By.xpath("//a[text()='Free Sign Up']")); link.click(); WebElement organization=driver.findElement(By.xpath("//input[@name='organization']")); organization.sendKeys("LambdaTest"); WebElement first_name=driver.findElement(By.xpath("//input[@name='first_name']")); first_name.sendKeys("Test"); WebElement last_name=driver.findElement(By.xpath("//input[@name='last_name']")); last_name.sendKeys("User"); WebElement email=driver.findElement(By.xpath("//input[@name='email']")); email.sendKeys("sadhvi.singh@navyuginfo.com"); WebElement password=driver.findElement(By.xpath("//input[@name='password']")); password.sendKeys("TestUser123"); WebElement phone_number=driver.findElement(By.xpath("//input[@name='phone']")); phone_number.sendKeys("9412262090"); WebElement button=driver.findElement(By.xpath("//button[text()='SIGN UP']")); button.click(); Thread.sleep(3500); String url= driver.getCurrentUrl(); assertEquals("fail- unable to register", url, "https://accounts.lambdatest.com/user/email-verification"); }
Here, the method name 'Register_User 'explicitly defines the user by name, indicating that the method contains code related to user registration. Likewise, all Web elements or variables have names associated with the capture fields used to define the intent.
In general, camel case is encouraged to record methods or variables because it is clearer in terms of readability and maintenance scripts.
2. Reduce, reuse and recycle
It's important to ensure that your methods are broken down into the smallest blocks of the user's scene. They should cover simple and single processes. Don't make your approach too complex with multiple functions covered by a single approach. For example, the login feature requires users to be registered on the application. Keep your registration function in another method, if necessary, call this method in the login method. Reducing the complexity of the method can simplify the maintainability of the code.
In addition, do not copy and paste the same code into different methods if you need to reuse your methods. This leads to unnecessary duplication and redundancy in the code. Adding lines doesn't mean you've written good code. Refactoring and optimizing code is the key to writing stable, robust and better automated code.
Recycling is another useful technique for writing better automated code. I have experienced people who can automate legacy systems and don't tend to change existing methods in the automation framework without overriding another method when existing functionality changes. It just makes the framework vulnerable. Whenever the process changes, always update the existing method. Although it has its own challenge that new users may not know the possible dependency of the method, I think we should always look at the problem in the long run, rather than achieve those shorter goals.
The following is an example of how to simplify the login code into a small part of the function and use another registration method to simplify the whole process.
@Test public void Register_User() throws InterruptedException { driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS); driver.get("https://www.lambdatest.com/ "); driver.manage().window().maximize(); WebElement link= driver.findElement(By.xpath("//a[text()='Free Sign Up']")); link.click(); WebElement organization=driver.findElement(By.xpath("//input[@name='organization']")); organization.sendKeys("LambdaTest"); WebElement first_name=driver.findElement(By.xpath("//input[@name='first_name']")); first_name.sendKeys("Test"); WebElement last_name=driver.findElement(By.xpath("//input[@name='last_name']")); last_name.sendKeys("User"); WebElement email=driver.findElement(By.xpath("//input[@name='email']")); email.sendKeys("sadhvi.singh@navyuginfo.com"); WebElement password=driver.findElement(By.xpath("//input[@name='password']")); password.sendKeys("TestUser123"); WebElement phone_number=driver.findElement(By.xpath("//input[@name='phone']")); phone_number.sendKeys("9412262090"); WebElement button=driver.findElement(By.xpath("//button[text()='SIGN UP']")); button.click(); } @Test public void Login_User() { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("User2@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("TestUser123"); driver.findElement(By.xpath("//button[@class='sign-up-btn']")).click(); } @AfterClass public static void BrowserClose() { driver.quit(); } }
3. Reasonably organize the test
Well, this is really one of the main actionable insights to ensure better automation code. It's not only easy to understand, but it doesn't take much effort to maintain. In the long run, building tests with frameworks can add value and reduce maintenance. You can control the flow of your application by using annotations provided by frameworks such as JUnit and TestNG. For example, using annotations such as @ BeforeClass can help you guide time-consuming activities, such as connecting to a database, setting up a browser, and other code related to this method, as well as the @ BeforeClass annotation associated with it. This helps the automated tester immediately know the exact function of the method and when to call it. Imagine that your setup process is clear and has been sorted out from the rest of the code.
The following example highlights a better structured approach through the TestNG framework:
import static org.junit.Assert.*; import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class Lamdatest { static WebDriver driver; @BeforeClass public static void BrowserOpen() { System.setProperty("webdriver.chrome.driver", "chromepath"); driver= new ChromeDriver() ; driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); } @Test(priority=1) public void Register_User() throws InterruptedException { driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS); driver.get("https://www.lambdatest.com/ "); driver.manage().window().maximize(); WebElement link= driver.findElement(By.xpath("//a[text()='Free Sign Up']")); link.click(); WebElement organization=driver.findElement(By.xpath("//input[@name='organization']")); organization.sendKeys("LambdaTest"); WebElement first_name=driver.findElement(By.xpath("//input[@name='first_name']")); first_name.sendKeys("Test"); WebElement last_name=driver.findElement(By.xpath("//input[@name='last_name']")); last_name.sendKeys("User"); WebElement email=driver.findElement(By.xpath("//input[@name='email']")); email.sendKeys("sadhvi.singh@navyuginfo.com"); WebElement password=driver.findElement(By.xpath("//input[@name='password']")); password.sendKeys("TestUser123"); WebElement phone_number=driver.findElement(By.xpath("//input[@name='phone']")); phone_number.sendKeys("9412262090"); WebElement button=driver.findElement(By.xpath("//button[text()='SIGN UP']")); button.click(); String url= driver.getCurrentUrl(); assertEquals("fail- unable to register", url, "https://accounts.lambdatest.com/user/email-verification"); } @Test(dependsOnMethods="Register_User") public void Login_User() { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("User2@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("TestUser123"); driver.findElement(By.xpath("//button[@class='sign-up-btn']")).click(); } @AfterClass public static void BrowserClose() { driver.quit(); } }
It is important to determine which annotations should be associated with which test method. With clear dependencies and priorities, tests and code can be constructed based on the flow of the application.
4. Fully verify your test
As a quality inspector, all you have to do is verify your expected and actual satisfaction, which is the same as your automation code. If your script doesn't meet the validation requirements, there's no point in creating a script. Ideally, every user action should be validated just like a test case step, whether it's validating element visibility, remembering layout cues, text representations, page redirection or any form of visual validation, or even evaluating the results of a data base.
Even if your validation cannot be determined, a failure message is displayed so that you can find out the problem. The biggest mistake we make in validating code is to write it from the perspective of ensuring that validation passes. We never thought about what would happen if the code failed or didn't work as expected, and what would be needed to continue.
If you want to break the test and jump to another test immediately after a validation failure, you can use hard assertions, and if you want to validate multiple checks on the same page, you can choose soft assertions. Deciding which assertion to use entirely depends on the use case.
The following is an example of assertions performed on the login page. In this method, you create a method in which you log in to the user with valid credentials, and then use another method to ensure that the user does not log in with invalid credentials and display an error message.
//validate user able to login with valid credentials @Test public void Login_User() throws IOException { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("User2@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("TetsUser123"); driver.findElement(By.xpath("//button[@class='sign-up-btn']")).click(); WebDriverWait wait= new WebDriverWait(driver, 15); wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//a[@class='user-profile dropdown-toggle']")))); String Current_url= driver.getCurrentUrl(); Assert.assertEquals("https://accounts.lambdatest.com/user/email-verification", Current_url); System.out.println("user logged in sucesfully"); driver.findElement(By.xpath("//a[@class='user-profile dropdown-toggle']")).click(); driver.findElement(By.xpath("//a[contains(text(),'Logout')]")).click(); } //validate user is unable to login with invalid credentials @Test public void Login_invalid_User() throws IOException { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("User21@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("TestUser123"); driver.findElement(By.xpath("//button[@class='sign-up-btn']")).click(); WebDriverWait wait= new WebDriverWait(driver, 15); String str= driver.findElement(By.xpath("//p[@class='error-mass']")).getText(); String Current_url= driver.getCurrentUrl(); Assert.assertEquals("https://accounts.lambdatest.com/login", Current_url); System.out.println(str); }
There may be different ways to override multiple validation checks, or you can choose different methods for each validation as I did above, or you can choose to do all validation in a single method under the try catch block.
5.sleep can not improve stability
The biggest myth we tend to believe in, especially when we first touch the automation field, is that by providing enough waiting for scripts, necessary or unnecessary waiting will lead to script execution smoothly. Instead, it makes the script unstable and increases the overall execution time. The main problem with this kind of static sleep is that we don't understand the load on the machine running the test, so it can lead to a timeout. Therefore, use should be avoided thread.sleep To maintain better automation code. A better way to use waiting for scripts is through conditional binding, where scripts can wait like humans until certain conditions are met. For example, wait until an element is visible or invisible.
As an option for developing better automated code, explicit and fluent waiting is more adaptive.
6. Test, data driven
Testing becomes more efficient when testing multiple forms of data, as well as when writing better automated code to test Web applications or any other software. In automation, the key is to test the code through various forms of data, rather than writing different test scripts for each data. This can be easily achieved through a data-driven test framework. It helps to store test data input into external databases, such as CSV files, excel files, text files, XML files and even ODBC repositories. This data is called into the script and run again and again in the same test code. This helps reduce redundancy and speed execution compared to manual work. New bug s found. Another benefit of this approach is that it speeds up the test cycle by reducing the number of test scripts you may have to add.
Keeping it in sync also helps simplify script maintainability. If any changes occur to the application, all hard coded values in the code may be broken. A simpler way to do this is to set all hard coded components to variable driven. For example, by storing their respective values in the excel worksheet and calling them in the script, all locators are not subject to code restrictions. In case any of your locators are damaged, you only need to change the value of the locators in Excel without touching the script at all.
A basic example of data-driven testing is:
public void Login_User() throws IOException { File f1= new File("C://Users//navyug//Desktop//Test.xlsx"); FileInputStream scr= new FileInputStream(f1); XSSFWorkbook book= new XSSFWorkbook(scr); XSSFSheet sheet=book.getSheetAt(0); for(int i=0; i<=sheet.getLastRowNum(); i++ ) { //XSSFCell cell= sheet.getRow(i).getCell(1); Row row = sheet.getRow(i); Cell cell = row.getCell(0); driver.findElement(By.xpath("//input[@name='email']")).sendKeys(cell.toString()); cell= row.getCell(1); driver.findElement(By.xpath("//input[@name='password']")).sendKeys(cell.toString()); driver.findElement(By.xpath("//button[@class='sign-up-btn']")).click(); WebDriverWait wait= new WebDriverWait(driver, 15); wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//a[@class='user-profile dropdown-toggle']")))); String Current_url= driver.getCurrentUrl(); Assert.assertEquals("https://accounts.lambdatest.com/user/email-verification", Current_url); System.out.println("user logged in sucesfully"); takescreenshot(); driver.findElement(By.xpath("//a[@class='user-profile dropdown-toggle']")).click(); driver.findElement(By.xpath("//a[contains(text(),'Logout')]")).click(); } }
The above code shows the data obtained from Excel for different login credentials. The same function can be extended for XPath, where the XPath value can also be extracted from excel. Here, the key point to solve by data-driven method is to delete hard coded values from our code, make them variable oriented, and make them run the same code in multiple groups of inputs.
7. Don't miss the report!
If the automation code does not report the results to you, it will not work properly. In order to optimize your work as an automation engineer, it is important to know which test code passed and which failed with screenshots. The best ROI you can show stakeholders is through reporting. Sharing these detailed reports provides visibility and reduces the time you spend validating test execution scripts. You can use TestNG HTML report generation, JUnit report generation and other technologies to implement reports, or you can use the extension library to implement reports.
The following code shows an example, in which the screenshot has been taken after the completion of the login function as proof of passing the verification, and the following is an example of TestNG report generated after execution:
//validate user able to login with valid credentials @Test public void Login_User() throws IOException { driver.get("https://accounts.lambdatest.com/login"); driver.findElement(By.xpath("//input[@name='email']")).sendKeys("User2@gmail.com"); driver.findElement(By.xpath("//input[@name='password']")).sendKeys("TetsUser123"); driver.findElement(By.xpath("//button[@class='sign-up-btn']")).click(); WebDriverWait wait= new WebDriverWait(driver, 15); wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//a[@class='user-profile dropdown-toggle']")))); String Current_url= driver.getCurrentUrl(); Assert.assertEquals("https://accounts.lambdatest.com/user/email-verification", Current_url); System.out.println("user logged in sucesfully"); takescreenshot(); driver.findElement(By.xpath("//a[@class='user-profile dropdown-toggle']")).click(); driver.findElement(By.xpath("//a[contains(text(),'Logout')]")).click(); } public void takescreenshot() throws IOException { TakesScreenshot scr= ((TakesScreenshot)driver); File file1= scr.getScreenshotAs(OutputType.FILE); FileUtils.copyFile(file1, new File("C:\\Users\\navyug\\Desktop\\Login_user.PNG")); }
If for software testing, interface testing, automation testing, interview experience exchange. If you are interested, you can add software test exchange: 1085991341, and there will be technical exchanges with peers.
8. Don't forget to test across browsers!
Today, all Web applications support multiple browsers and versions. It is important that your code be targeted at multiple browsers, not specific browsers. Running code on a specific browser loses cross browser compatibility of the application. We can extend the automation of cross browser testing to ensure that your application provides a seamless user experience across all major browsers. Frameworks such as TestNG make it easy to perform tests in a variety of browsers.
The following code shows how to run automation code on multiple browsers through TestNG
public class crowssbrowser { static WebDriver driver; @Parameters("browser") @BeforeClass public static void Browser_Select(String browser) { if(browser.equalsIgnoreCase("firefox")) { System.setProperty("webdriver.firefox.marionette", "geckodriverpath"); driver = new FirefoxDriver(); // If browser is IE, then do this }else if (browser.equalsIgnoreCase("chrome")) { // Here I am setting up the path for my IEDriver System.setProperty("webdriver.chrome.driver", "chromedriverpath"); driver= new ChromeDriver() ; } driver.get("https://accounts.lambdatest.com/login"); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); }
XML code:
<?xml ve rsion="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite" parallel="none"> <test name="FirefoxTest"> <parameter name="browser" value="firefox" /> <classes> <class name="crowssbrowser" /> </classes> </test> <test name="chrometest"> <parameter name="browser" value="chrome" /> <classes> <class name="crowssbrowser" /> </classes> </test> </suite>
The above code shows a browser based method with different browser drivers set. Using the TestNG XML file, we have passed the parameters to different browsers where we will run the code for the login function on Firefox and chrome.
The above content is the whole content of this article. I hope that the above content can help you. If you have any friends who are helped, please comment.