Clean Code in Test Automation Differentiating Between the Good and the Bad

knoldus 22 views 27 slides May 22, 2024
Slide 1
Slide 1 of 27
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27

About This Presentation

This session focuses on the principles of writing clean, maintainable, and efficient code in the context of test automation. The session will highlight the characteristics that distinguish good test automation code from bad, ultimately leading to more reliable and scalable testing frameworks.


Slide Content

Clean Code In Test Automation Presented By Lokeshwaran Subramaniyan Software Consultant Test Automation Competency Lokeshwaran Subramaniyan Software Consultant Test Automation Competency Lokeshwaran Subramaniyan Software Consultant Test Automation Competency Lokeshwaran Subramaniyan Software Consultant Test Automation Competency Lokeshwaran Subramaniyan Software Consultant Test Automation Competency Aditya Kumar Singh Automation Consultant (Test Automation Competency)

Introduction Clean Testing (Arrange -> Act -> Assert) Characteristics Of Good Test Automation Code Of Bad Test Automation Code Clean Code Principles in Test Automation Best Practices in Test Automation

Introduction Writing clean code is paramount for ensuring that tests are effective, maintainable, and reliable. Clean code in test automation not only facilitates easier understanding and modification by team members but also enhances the overall quality and performance of the test suite. The focus will be on differentiating between good and bad practices in test automation, highlighting the characteristics of well-written tests and common pitfalls to avoid. By examining these distinctions, we aim to promote best practices that lead to more efficient and robust automated testing.

Clean Testing Clean Testing is a methodology in test automation that emphasizes writing clear, readable, and maintainable tests by following a structured pattern known as Arrange-Act-Assert (AAA) .  This pattern ensures that tests are easy to understand and consistently organized, which helps in identifying and fixing issues quickly. Like clean code, a clean test is simple, direct, and not cluttered with unnecessary steps or information.

Arrange -> Act -> Assert Arrange  In the Arrange phase, you set up everything needed for the test. This includes: Initializing Objects : Create instances of the classes you will test. Setting Up Data : Prepare any data or state required for the test. Mocking Dependencies : Use mocks or stubs for any external dependencies. @BeforeClass
    public void setUp () {
        // Arrange
        System .setProperty (" webdriver.chrome.driver ", "path/to/ chromedriver ");
        driver = new ChromeDriver ();
        driver.manage (). window ().maximize();
        driver. get ("https://example.com/login");
    }

Arrange -> Act -> Assert Act In the Act phase, you perform the action that you want to test.  This typically involves calling a method or function. Or Simply,  Choose an action that will trigger the test result – this could be a click, calling a specific function, or something else. @Test
    public void testLogin () {
        // Arrange
        WebElement usernameField = driver.findElement ( By .id("username"));
        WebElement passwordField = driver.findElement ( By .id("password"));
        WebElement loginButton = driver.findElement ( By .id(" loginButton "));

        // Act
        usernameField.sendKeys (" testuser ");
        passwordField.sendKeys (" testpassword ");
        loginButton.click ();
}

Arrange -> Act -> Assert Assert In the Assert phase, you verify that the outcome is as expected.  This is where you check the results of the action performed in the Act phase against the expected results. Or Assert the result was what was expected.    @Test
    public void testLogin () {
        // Arrange
        WebElement usernameField = driver.findElement ( By .id("username"));
        WebElement passwordField = driver.findElement ( By .id("password"));
        WebElement loginButton = driver.findElement ( By .id(" loginButton "));

        // Act
        usernameField.sendKeys (" testuser ");
        passwordField.sendKeys (" testpassword ");
        loginButton.click ();

        // Assert
        WebElement welcomeMessage = driver.findElement ( By .id(" welcomeMessage "));
        Assert.assertTrue ( welcomeMessage.isDisplayed (), "Login failed: Welcome message is not displayed.");
        Assert.assertEquals ( welcomeMessage.getText (), "Welcome, testuser !", "Login failed: Incorrect welcome message.");
    }

Characteristics Of Good Automation Code Good automation code is essential for ensuring reliability, efficiency, and maintainability in automated processes. Here are some key characteristics of well-written automation code: Readability Clear and Concise : The code should be easy to read and understand.  Consistent Naming Conventions : Adopting a consistent style for naming variables, functions, and classes. Comments: Appropriate comments help others (and your future self) understand the code's functionality and intent. Modularity Functions and Modules : Breaking down the code into reusable functions and modules makes it easier to manage. Single Responsibility : Each function or module should have a single, well-defined responsibility. Flexibility and Configurability Configurable Parameters : Using configuration files or environment variables allows the code to be easily adapted to different environments or use cases without modifying the codebase. Extensibility : The code should be designed to accommodate future changes or additional features with minimal modifications. Error Handling and Logging Error Handling : Proper error handling mechanisms should be in place to gracefully handle exceptions and errors without crashing. Logging : Implementing logging helps in debugging and provides insights into the code's execution flow.

Characteristics Of Good Automation Code Compliance and Standards Adherence to Standards : Following industry standards and best practices for coding ensures that the automation code is reliable and interoperable. Code Reviews : Regular code reviews help identify issues early and improve the overall quality of the code. Security Secure Practices : Following best security practices, such as avoiding hard-coded credentials and using secure connections, protects against vulnerabilities. Input Validation : Validating inputs ensures that the code handles unexpected or malicious data appropriately. Scalability Efficient Algorithms : Writing efficient algorithms ensures that the code can handle increasing amounts of data or complexity without significant performance degradation. Parallelization : Where possible, enabling parallel execution of tasks can improve performance.

Characteristics Of Bad Automation Code Bad automation code can lead to inefficiencies, difficulties in maintenance, and potential failures in automated processes. Here are some characteristics that typically define poor automation code: Poor Readability Unclear Naming : Using non-descriptive variable and function names that do not convey their purpose. Inconsistent Style : Inconsistent naming conventions and coding styles, leading to confusion and difficulty in following the code. Lack of Comments : Absence of comments or documentation, making it difficult to understand the code’s intent and functionality. Monolithic Structure Lack of Modularity : Writing large, monolithic blocks of code without breaking them down into smaller, reusable functions or modules. Multiple Responsibilities : Functions or modules that handle multiple tasks, making them complex and difficult to understand or reuse. Redundancy Code Duplication : Repeating the same code in multiple places instead of abstracting common functionality into reusable components. Weak Error Handling No Error Handling : Failing to handle potential errors or exceptions, which can cause the automation to crash unexpectedly. Poor Logging : Inadequate or absent logging, making it hard to diagnose issues or understand the code’s execution flow.

Characteristics Of Bad Automation Code Non-Adherence to Standards Ignoring Best Practices : Not following industry best practices and coding standards, leading to lower quality and less reliable code. No Code Reviews : Skipping code reviews, missing out on opportunities to catch issues early and improve code quality. Security Vulnerabilities Hardcoded Credentials : Storing sensitive information like credentials directly in the code, which can be a major security risk. Lack of Input Validation : Failing to validate inputs, making the code vulnerable to injection attacks and other security issues. Hardcoding and Inflexibility Hardcoded Values : Using hardcoded values for configurations, making the code less flexible and harder to adapt to different environments. Non-Configurable : Lack of configurable parameters, requiring code changes for different use cases or environments.

Clean Code Principles in Test Automation Single Responsibility Principle This principle states that a class or module should have only one reason to change.  In test automation, this means that each test case or test suite should focus on testing a single piece of functionality.  It helps in maintaining the tests, as any change in the feature being tested should only require changes in one place.

Clean Code Principles in Test Automation Open/Closed Principle The Open/Closed Principle suggests that software entities (classes, functions, etc.) should be open for extension but closed for modification.  In test automation, this could mean that your test cases should be designed in a way that allows for easy extension (adding new test cases) without modifying existing ones.  This could be achieved through proper abstraction and use of design patterns like Page Object Model.

Clean Code Principles in Test Automation FIRST Principle FIRST stands for Fast, Isolated/Independent, Repeatable, Self-Validating, and Timely. Fast: Tests should execute quickly to provide rapid feedback. Isolated/Independent: Tests should not depend on each other. Each test should be able to run independently. Repeatable: Tests should produce the same result every time they are run. Self-Validating: Tests should have a Boolean output. They should pass or fail clearly. Timely: Tests should be written timely, ideally before the code they are testing is implemented, following a test-driven development (TDD) approach.

Clean Code Principles in Test Automation Single Level of Abstraction Principle This principle states that there should not be multiple levels of abstraction within a function or method.  In test automation, this means that test methods should have a single level of abstraction, making them easier to read and understand.

Clean Code Principles in Test Automation Dependency Injection Principle This principle promotes injecting dependencies into a class rather than creating them internally.  In test automation, this allows for easier testing by enabling the injection of mock objects or test doubles to isolate the component under test.

Best Practices in Test Automation Descriptive Naming Lorem Ipsum is simply dummy text of the printing . Lorem Ipsum is simply dummy text of the printing . Small And  Focused Tests Page Object Model Parameterized Values Assertions Waits Logging And Reporting

Best Practices in Test Automation Use Descriptive Naming In test automation, Choose descriptive names for classes, methods, and variables that convey their purpose. For Example, public class LoginPageTest {

    @Test
    public void loginWithValidCredentials_shouldSucceed () {
        // Arrange: Set up the test scenario
        WebDriver driver = new ChromeDriver ();
        LoginPage loginPage = new LoginPage (driver);

        // Act: Perform the login operation
        loginPage.navigate ();
        loginPage.login ( TestConstants.VALID_USERNAME , TestConstants.VALID_PASSWORD );

        // Assert: Verify the expected outcome
        assertTrue ("Login successful", driver.getTitle ().contains("Dashboard"));

        // Clean up: Close the browser
        driver.quit ();
    }
}

Best Practices in Test Automation Keep Tests Small and Focused In test automation, each test should focus on testing a single functionality or scenario. For Example, // Validating the login page @Test                                                                                                                                                                                        public void loginWithValidCredentials_shouldSucceed() {       // Arrange: Set up the test scenario
      WebDriver driver = new ChromeDriver();
       LoginPage loginPage = new LoginPage(driver);       // Act: Perform the login operation       loginPage.navigate();
       loginPage.login ( TestConstants.VALID_USER , TestConstants.VALID_PASS);       // Assert: Verify the expected outcome
      assertTrue("Login successful", driver.getTitle(). contains ("Dashboard"));

      // Clean up: Close the browser
       driver.quit();     } // Validating the home page @Test   public void navigateToHomePage_afterSuccessfulLogin() {
      // Arrange: Set up the test scenario
      WebDriver driver = new ChromeDriver();
       LoginPage loginPage = new LoginPage(driver);
       HomePage homePage = new HomePage(driver);

      // Act: Perform the login operation        loginPage.navigate ();
       loginPage.login ( TestConstants.VALID_USER , TestConstants.VALID_PASS );

      // Act: Navigate to the home page
       homePage.navigateToHomePage ();

      // Assert: Verify the expected outcome
       assertTrue ("Home page is displayed", homePage.isHomePageDisplayed ());

      // Clean up: Close the browser
       driver.quit ();
    }

Best Practices in Test Automation Use Page Object Model (POM) In test automation, encapsulate web elements and actions into Page Objects to promote reusability and maintainability. For Example, import org.openqa.selenium.By ; import org.openqa.selenium.WebDriver ;

public class LoginPage {
    private WebDriver driver;
    private By usernameInput = By.id("username");
    private By passwordInput = By.id("password");
    private By loginButton = By.id("login");

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

    public void navigate() {
        driver.get ( TestConstants.BASE_URL + "/login");
    }

    public void login(String username, String password) {
        driver.findElement ( usernameInput ). sendKeys (username);
        driver.findElement ( passwordInput ). sendKeys (password);
        driver.findElement ( loginButton ).click();
    }
}

Best Practices in Test Automation Avoid Hardcoding Values In test automation, use configuration files or constants to store test data and configuration settings. For Example, import org.openqa.selenium.By ; import org.openqa.selenium.WebDriver ;

public class LoginPage {
    private WebDriver driver;
    private By usernameInput = By.id("username");
    private By passwordInput = By.id("password");
    private By loginButton = By.id("login");

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

    public void navigate() {
        driver.get ( TestConstants.BASE_URL + "/login");
    }

    public void login(String username, String password) {
        driver.findElement ( usernameInput ). sendKeys (username);
        driver.findElement ( passwordInput ). sendKeys (password);
        driver.findElement ( loginButton ).click();
    }
} // Example:
public class TestConstants {
    public static final String BASE_URL = "https://example.com";
    public static final String USERNAME = " testuser ";
    public static final String PASSWORD = "password123";
}

Best Practices in Test Automation Keep Assertions Clear and Concise In test automation, use meaningful messages in assertions to understand failures easily. For Example, @Test
    public void loginWithValidCredentials_shouldSucceed () {
        // Arrange: Set up the test scenario
        WebDriver driver = new ChromeDriver ();
        LoginPage loginPage = new LoginPage (driver);
        HomePage homePage = new HomePage (driver);

        // Act: Perform the login operation         loginPage.navigate ();
        loginPage.login ( TestConstants.VALID_USER , TestConstants.VALID_PASS );

        // Assert: Verify the expected outcome
        assertEquals ("The page title should be 'Dashboard' after successful login", "Dashboard", driver.getTitle ());

        // Clean up: Close the browser
        driver.quit ();
    } // Example: assertEquals ("Login successful", driver.getTitle ());

Best Practices in Test Automation Handle Waits Properly In test automation, use explicit and implicit waits to handle synchronization issues. For Example,     @BeforeMethod
    public void setUp () {
        // Set up the ChromeDriver path
        System.setProperty (" webdriver.chrome.driver ", "path/to/ chromedriver ");

        // Initialize the ChromeDriver         driver = new ChromeDriver ();

        // Set implicit wait (applies to all elements)
        driver.manage ().timeouts(). implicitlyWait (10, TimeUnit.SECONDS );

        // Initialize WebDriverWait (explicit wait)
        wait = new WebDriverWait (driver, 10);

        // Navigate to the desired URL
        driver.get ("https://example.com");
    } // Example: WebDriverWait wait = new WebDriverWait (driver, 10); wait. until ( ExpectedConditions.visibilityOfElementLocated (By.id(" elementId ")));

Best Practices in Test Automation Parameterize Tests In test automation, use parameterization to run tests with different data sets. For Example,    @Test(dataProvider = " loginData ")
    public void loginWithValidCredentials_shouldSucceed (String username, String password) {
        // Act: Perform the login operation         loginPage.navigate ();
        loginPage.login (username, password);

        // Assert: Verify the expected outcome
        assertEquals ( driver.getTitle (), "Dashboard", "The page title should be Dashboard'");
    }

    @Test(dataProvider = " loginData ")
    public void navigateToHomePage_afterSuccessfulLogin (String username, String password) {
        // Act: Perform the login operation         loginPage.navigate ();
        loginPage.login (username, password);

        // Act: Navigate to the home page
        homePage.navigateToHomePage ();

        // Assert: Verify the expected outcome
        assertTrue ( homePage.isHomePageDisplayed (), "The home page should be displayed after navigation");
    } // Example:
@DataProvider(name = " loginData ")
    public Object [][] loginData () {
        return new Object [][] {
            {"username1", "password1"},
            {"username2", "password2"}
        };
    }

Best Practices in Test Automation Implement Logging and Reporting In test automation, use logging frameworks like Log4j or SLF4J to log informative messages for debugging. Utilize reporting tools like ExtentReports or TestNG reports for generating comprehensive test reports. For Example,     @Test(dataProvider = " loginData ")
    public void loginWithValidCredentials_shouldSucceed (String username, String password) {
        test = extent.createTest (" loginWithValidCredentials_shouldSucceed with " + username);

        logger.info("Starting login test with username: " + username);
        test.log(Status.INFO, "Starting login test with username: " + username);

        // Act: Perform the login operation         loginPage.navigate ();
        test.log(Status.INFO, "Navigated to login page");
        loginPage.login (username, password);
        test.log(Status.INFO, "Performed login with username: " + username);

        // Assert: Verify the expected outcome
        String expectedTitle = "Dashboard";
        String actualTitle = driver.getTitle ();
        logger.info("Verifying the page title. Expected: " + expectedTitle + ", Actual: " + actualTitle );
        test.log(Status.INFO, "Verifying the page title. Expected: " + expectedTitle + ", Actual: " + actualTitle );  } } // Example:
Logger logger = Logger.getLogger ( LoginPageTest.class.getName ());
logger.info("Login test started...");

DEMO
Tags