30

Test Automation: Seamless Integration of Tools and Frameworks

 4 years ago
source link: https://www.tuicool.com/articles/ziYZjyy
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

In this article, I want to give you an overview of how well the latest technologies can be integrated seamlessly into a test automation framework. Test automation is also an integral part of the software development lifecycle, and we want our test automation framework to contain all the latest features with minimal effect.

In this article, we build a sample test automation framework that consists of tools likeSpring Boot, Cucumber,Java 8, and Serenity to test a sample Calculator application.

You may also enjoy: A Complete Guide to Test Automation Frameworks

There is a simple calculator application, which returns the sum of two numbers.

Sample Application:

package com.example.serenitycucumber;

public class Calculator {

public int add(int firstNumber, int secondNumber) {
             return firstNumber + secondNumber;
          }
}

Let's start with the designing of the test automation framework.

ZjMbq27.jpg!web

Test automation framework design

As shown above in the design depicture, the test automation framework consists of four major pillars.

  1. Spring Boot Test: Provides a number of utilities and annotations to help when writing test automation code like auto-configuration and dependency injection.
  2. Java 8 Lambda : Provides a clear and concise way to represent one method interface usieng an expression.
  3. Serenity BDD: Reporting is one of Serenity’s strengths. Serenity not only reports on whether a test passes or fails, but has live documentation on what it did in a step-by-step narrative format that includes test data and screenshots.
  4. Cucumber 4: Last 2-3 years, cucumber has changed a lot, it will be good if our test automation contains all the new cucumber features.

Let’s jump into the coding part of how we can integrate all these together in one test automation framework.

Test Automation Framework

For the first step, create a sample Maven Java project and under the source folder, create a new end-to-end folder, e2e, where we will place all our end-to-end test automation code.

Note: Thise2e has to be added to the project classpath.

M7rMBjY.png!web

Adding e2e folder

For the next step, add the jar dependencies mentioned below to a .pom file.

Maven Dependencies

<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>2.0.70</version>
<exclusions>
<exclusion>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-cucumber4</artifactId>
<version>1.0.21</version>
<exclusions>
<exclusion>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/net.serenity-bdd/serenity-spring -->
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-spring</artifactId>
<version>2.0.70</version>
<exclusions>
<exclusion>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java8</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>4.2.0</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<includes>
<include>TestRunner.java</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>net.serenity-bdd.maven.plugins</groupId>
<artifactId>serenity-maven-plugin</artifactId>
<version>2.0.70</version>
<executions>
<execution>
<id>serenity-reports</id>
<phase>post-integration-test</phase>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>net.serenity-bdd</groupId>
<artifactId>serenity-core</artifactId>
<version>2.0.70</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

BDD Feature File

The next step creates a feature file using Gherkin syntax (e.g. Given, When, Then) under the resources folder.

In6bmye.png!web

BDD feature file

Every statement in the scenario starts with a keyword (like Given, And, When, Then) that serves a special meaning and eventually invokes a method from a Step Definition class.

BDD Step Definition

Next create a concrete calculator step definition Java class which extends the base step definition Java file.

Note: This Java file using a Java 8 method references the GIVEN, THEN, THEN statement.

package com.example.serenitycucumber.stepdefinition;

import static org.junit.Assert.assertEquals;

import org.springframework.beans.factory.annotation.Autowired;
import com.example.serenitycucumber.steps.CalculatorSteps;
import com.example.serenitycucumber.util.Context;

import cucumber.api.java8.En;
import net.serenitybdd.core.Serenity;

/**
 * 
 * @author ravi kumar
 * This is a step definition class for calculator functionality.
 *
 */
public class CalculatorStepdefs extends BaseStepDefinition implements En {

@Autowired
CalculatorSteps calculatorStep;

@Autowired
private Context context;

public CalculatorStepdefs() {

Given("^I have a Calculator$", this::initializeCalculator);
When("^I add (\\d+) and (\\d+)$", this::testAdd);
Then("^the sum should be (\\d+)$", this::validateResult);
}

private void initializeCalculator() {
calculatorStep.setUpCalculator();
}

private void testAdd(final int firstNumber, final int secondNumber) throws Throwable {
final Integer actualSumValue = calculatorStep.whenAddTwoNumbers(firstNumber, secondNumber);
Serenity.recordReportData().withTitle("Actual add result").andContents(actualSumValue.toString());
context.setValue("actualSum",actualSumValue);

}

private void validateResult(final int result) throws Throwable {
assertEquals("The expected sum does not equal the actual sum", result, (int)context.getValue("actualSum"));
}
}

The next step creates a base step definition Java file where we put a Spring integration class-level rule and this step definition Java file will be extended by the other concrete step definition Java class.

Note: The @SpringBootTest annotations load the Spring context and configuration file.

package com.example.serenitycucumber.stepdefinition;

import org.junit.ClassRule;
import org.springframework.boot.test.context.SpringBootTest;

import com.example.serenitycucumber.config.Config;

import net.serenitybdd.junit.spring.integration.SpringIntegrationClassRule;

/**
 * 
 * @author ravi kumar
 * This is a base step definition class used/extends by every other step definition class.
 *
 */

@SpringBootTest(classes = Config.class)
public abstract class BaseStepDefinition {

 @ClassRule
    public static SpringIntegrationClassRule springIntegrationClassRule = new SpringIntegrationClassRule();


}

Serenity BDD

Next, create a separate layer of Java files where we will place complex test-related code.

package com.example.serenitycucumber.steps;

import com.example.serenitycucumber.Calculator;

/**
 * 
 * @author ravi kumar
 *
 */
public class CalculatorSteps {

private Calculator calculator;

public void setUpCalculator() {
this.calculator = new Calculator();
}

public Integer whenAddTwoNumbers(final int firstNumber, final int secondNumber) {
return calculator.add(firstNumber, secondNumber);

}



}

BDD Runner

Here, we define cucumber optional values and runner type @RunWith CucumberWithSerenity and provide the facility to put everything together.

package com.example.serenitycucumber.runner;

import cucumber.api.CucumberOptions;
import cucumber.api.SnippetType;
import net.serenitybdd.cucumber.CucumberWithSerenity;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import com.example.serenitycucumber.config.Config;

/**
 * 
 * @author ravi kumar
 * This is a runner file where we specify the cucumber options parameter value.
 */
@RunWith(CucumberWithSerenity.class)
@CucumberOptions(
        plugin = {"pretty", "json:build/reports/cucumber.json"},
        features = "src/e2e/resources/features/",
        snippets = SnippetType.CAMELCASE,
        glue = {"com.example.serenitycucumber"}, // packages used for glue code, looked up in the classpath
        tags = {"not @manual"} // security
)
@SpringBootTest(classes = Config.class)
public class TestRunner{



}

Spring Dependency Configuration

Now we put all the dependencies in one place, which helps us to manage the framework when it grows.

package com.example.serenitycucumber.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.serenitycucumber.steps.CalculatorSteps;
import com.example.serenitycucumber.util.Context;

/**
 * 
 * @author ravi kumar
 *
 * This is a test configuration file where we placed all the bean. 
 */
@Configuration
public class Config {


@Bean
@Qualifier("getCalculatorStep")
public CalculatorSteps getCalculatorStep() {
return new CalculatorSteps();
}

@Bean
@Qualifier("getContext")
public Context getContext() {
return new Context();
}

}

Here, we define the Cucumber hooks using lambda expressions.

package com.example.serenitycucumber.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.example.serenitycucumber.config.Config;
import cucumber.api.Scenario;
import cucumber.api.java8.En;

/**
 * 
 * @author ravi kumar
 *
 */
@SpringBootTest(classes = Config.class)
public class CucumberHooks implements En{

@Autowired
private Context context;

public CucumberHooks(){

Before((Scenario scenario) -> {
System.out.println("---- before scenario  ----".concat(scenario.getName()));
context.clearContext();
});

After((Scenario scenario) -> {
System.out.println("---- after scenario ----".concat(scenario.getName()));
});

}
}

This is a kind of container where we store intermediate values and later use these values further down in the code.

package com.example.serenitycucumber.util;

import java.util.HashMap;

/**
 * 
 * @author ravi kumar
 * This is a scenario context class used to save intermediate values.
 *
 */
public class Context {

private HashMap<String, Object> con;

public Context() {
con = new HashMap<>();
}

public Object getValue(String value) {
return con.get(value);

}

public void setValue(String key,Object value) {
con.put(key, value);
}

public void clearContext() {
con.clear();
}

public void removeValue(String key) {
con.remove(key);
}
}

Serenity Output Report

bYbEnum.png!web

Serenity output report

For reference, please see this Github link .

Further Reading

Top 17 Resources To Learn Test Automation In 2019

5 Integrations for Powerful Automation Testing


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK