TestNG was developed by a famous programmer named “Cedric Beust”. It is distributed under Apache Software License and is easily available to download. TestNG requires JDK 7 or higher. TestNG is a testing framework inspired by JUnit and NUnit, but introduces some new functionalities that make it more powerful and easier to use.
In this tutorial, we will get to know Log4j 2. An essential component of software development is event logging. Although there are many frameworks in the Java environment, Log4J has been the most well-liked for decades because of its simplicity and flexibility.
Apache Log4j is a Java-based logging utility. Apache Log4j 2 is an upgrade to Log4j that provides significant improvements over its predecessor, Log4j 1.x, and provides many of the improvements available in Logback while fixing some inherent problems in Logback’s architecture.
Apache Log4j2 versions 2.0-beta7 through 2.17.0 (excluding security fix releases 2.3.2 and 2.12.4) are vulnerable to a remote code execution (RCE) attack where an attacker with permission to modify the logging configuration file can construct a malicious configuration using a JDBC Appender with a data source referencing a JNDI URI which can execute remote code. This issue is fixed by limiting JNDI data source names to the java protocol in Log4j2 versions 2.17.1, 2.12.4, and 2.3.2.
Log4j Components
Log4j Loggers
Loggers provide a way to organize log messages based on their severity and purpose, making it easier to diagnose and troubleshoot issues in your code.
Types of Loggers in Log4j
There are two types of loggers in Log4j: root loggers and named loggers.
Root Logger: The root logger is the top-level logger in the Log4j hierarchy and is responsible for capturing all log messages in the application. By default, the root logger has a log level of DEBUG and sends log messages to the console appender.
Named Loggers: Named loggers are loggers that have been given a specific name and are used to log messages for specific parts of the application. You can create them for specific packages, classes, or even individual methods. They can have a different log level and appender than the root logger, making it possible to customize the logging for specific parts of
Log4j level
Primarily, there are five kinds of log levels
1. TRACE: The TRACE level is the lowest level of severity. You can use it for detailed log messages that are primarily useful for debugging purposes.
2. DEBUG: We use the DEBUG level for messages that provide detailed information about the application’s execution. We usually use these messages to help diagnose issues and problems.
3. INFO: The INFO level is used for messages that provide general information about the application’s progress. These messages are used to give an overview of what the application is doing.
4. WARN: The WARN level is used for messages that indicate a potential problem or issue with the application. These messages are used to alert developers to potential issues that need to be addressed.
5. ERROR: The ERROR level is used to indicate errors that might still allow the application to run.
6. FATAL: The FATAL level is the highest level of severity and is used for messages that indicate a critical failure in the application. These messages are used to alert developers to issues that have caused the application to stop functioning.
7. OFF: No logging
Appenders
It is used to deliver LogEvents to their destination. It decides what will happen with log information. In simple words, it is used to write the logs in a file. Following are a few types of Appenders.
1. File Appender: It writes log messages to a specified file.
2. Console Appender: Writes log messages to the console.
3. Rolling File Appender: They write log messages to a file and automatically roll over to a new file when the current file reaches a specified size.
4. Daily Rolling File Appender: Writes log messages to a file and automatically rolls over to a new file at a specified time interval.
5. JDBC Appender: It writes log messages to a database using JDBC.
6. SMTP Appender: Writes log messages to an email using SMTP.
Layouts
In Log4j, we use a layout to format log messages before they are written to an appender. There are several different types of layouts available in Log4j, each with its own strengths and weaknesses. The different types of Log4j layouts include:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log_Demo {
// Creating a logger
private static Logger logger = LogManager.getLogger();
// Log messages
public static void main(String[] args) {
logger.debug("It is a debug logger.");
logger.error("It is an error logger.");
logger.fatal("It is a fatal logger.");
logger.info("It is a info logger.");
logger.trace("It is a trace logger.");
logger.warn("It is a warn logger.");
}
}
The output of the above program is
We can observe that I have created a Logger using LogManager and explicitly using all the levels with a string message. We have used all the levels but in the console, we are seeing only two levels. Actually when we do not provide any configuration file(yet to be covered), by default Log4j uses a default configuration.
The default configuration, provided in the DefaultConfiguration class, will set up:
A ConsoleAppender attached to the root logger i.e. logs will be printed on the console.
A PatternLayout set to the pattern “%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} – %msg%n” attached to the ConsoleAppender
Note that by default Log4j assigns the root logger to Level.ERROR and those logs will be printed on the standard console.
Serenity BDD is an open-source library that aims to make the idea of living documentation a reality.
What is Rest Assured?
Rest Assured is one of the most powerful libraries for testing RESTful API using Java language. Rest-Assured is a Java-based library that is used to test RESTful Web Services. This library behaves like a headless Client to access REST web services. The rest-Assured library also provides the ability to validate the HTTP Responses received from the server.
Prerequisite
Java 17 installed
Maven installed
Eclipse or IntelliJ installed
Dependency List
Java 17
Maven – 3.9.5
Serenity – 4.0.18
Serenity Rest Assured – 4.0.18
Rest Assured – 5.3.2
JUnit – 4.13.2
Maven Surefire Plugin – 3.1.2
Maven Failsafe Plugin – 3.1.2
Maven Compiler Plugin – 3.11.0
Project Structure
Implementation Steps
Step 1 – Update the Properties section in Maven pom.xml
Step 4 – Create the Test Code in src/java/testdirectory
There are 2 ways to create the same test. One approach is to have a Definition file that contains all the test code as shown below.
package org.example.tests;
import io.restassured.response.Response;
import net.serenitybdd.rest.SerenityRest;
import org.json.JSONObject;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
public class Employee {
private static final String URL = "https://reqres.in/api";
public Response response;
int id = 2;
@Test
public void verifyValidUser() {
response = SerenityRest
.given()
.contentType("application/json")
.header("Content-Type", "application/json")
.when()
.get(URL + "/users/" + id);
SerenityRest.restAssuredThat(response -> response.statusCode(200)
.body("data.id", equalTo(2))
.body("data.email", equalTo("janet.weaver@reqres.in"))
.body("data.first_name", equalTo("Janet"))
.body("data.last_name", equalTo("Weaver")));
}
@Test
public void verifyCreateUser() {
JSONObject data = new JSONObject();
data.put("name", "Test");
data.put("job", "Test Architect");
response = SerenityRest
.given()
.contentType("application/json")
.header("Content-Type", "application/json")
.body(data.toString())
.when()
.post(URL + "/users");
SerenityRest.restAssuredThat(response -> response.statusCode(201)
.body("name", equalTo("Test"))
.body("job", equalTo("Test Architect")));
}
}
Another approach is that all tests are split into reusable blocks called “steps“. The main principle of the BDD approach is that we are trying to keep complexity to a high-level human-readable level. First of all, let’s create a separate package to keep our steps. It is always better to keep them separate as it shows which classes contain reusable components. It is better to make steps smaller. So let’s make separate reusable steps from our tests:
package org.example.steps;
import io.restassured.response.Response;
import net.serenitybdd.annotations.Step;
import net.serenitybdd.rest.SerenityRest;
import org.json.JSONObject;
import static org.hamcrest.Matchers.equalTo;
public class EmployeeSteps {
private static final String URL = "https://reqres.in/api";
public Response response;
@Step("Search user by id {0}")
public void sendUser(int id) {
response = SerenityRest
.given()
.contentType("application/json")
.header("Content-Type", "application/json")
.when()
.get(URL + "/users/" + id);
}
@Step("Create a new user")
public void createUser() {
JSONObject data = new JSONObject();
data.put("name", "Test");
data.put("job", "Test Architect");
response = SerenityRest
.given()
.contentType("application/json")
.header("Content-Type", "application/json")
.body(data.toString())
.when()
.post(URL + "/users");
}
@Step("Verify the status code {0}")
public void verifyStatusCode(int expectedStatusCode) {
SerenityRest.restAssuredThat(response -> response.statusCode(expectedStatusCode));
}
@Step("Verify the user id {0}")
public void verifyId(int expectedId) {
SerenityRest.restAssuredThat(response -> response.body("data.id", equalTo(expectedId)));
}
@Step("Verify the user first name {0}")
public void verifyFirstName(String expectedFirstName) {
SerenityRest.restAssuredThat(response -> response.body("data.first_name", equalTo(expectedFirstName)));
}
@Step("Verify the user last name {0}")
public void verifyLastName(String expectedLastName) {
SerenityRest.restAssuredThat(response -> response.body("data.last_name", equalTo(expectedLastName)));
}
@Step("Verify the user email {0}")
public void verifyEmail(String expectedEmail) {
SerenityRest.restAssuredThat(response -> response.body("data.email", equalTo(expectedEmail)));
}
@Step("Verify the new user name {0}")
public void verifyNewUserName(String expectedName) {
SerenityRest.restAssuredThat(response -> response.body("name", equalTo(expectedName)));
}
@Step("Verify the new user job {0}")
public void verifyNewUserJob(String expectedJob) {
SerenityRest.restAssuredThat(response -> response.body("job", equalTo(expectedJob)));
}
}
Now our steps are ready. Let’s refactor the main class with our tests:
One more important thing we added is the “@RunWith(SerenityRunner.class)” annotation on top of the class. As we have now organized our structure to meet some basic Serenity principles, we are ready to run the test using Serenity. This time (after we added the mentioned annotation) these tests will be run using the “SerenityRunner”. For that we can use exactly the same command to run our tests:
mvn clean verify
The output of the above program is
In the console, you should find printed messages for tests to start. At the same time under the target directory you can find the HTML-generated report we were talking about before:
You can open the report in any browser:
If you click on any test you should see a detailed description of the test steps:
One of the most important features of the Serenity and REST Assured integration is that by using detailed reporting, you can easily validate all requests and response details even if you are not adding any logs inside tests. Like the example above, for each executed REST request you can click the button “REST Query” and get a detailed request and response description:
There is another very useful Serenity Report – Serenity Symmary.html
As you can see, Serenity and REST Assured provide you with a wonderful combination. REST Assured keeps API testing clean and easy to maintain, while Serenity gives you outstanding test reporting and flexibility in running and grouping your tests inside a test suite.
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
GitLab is a web-based Git repository that provides free open and private repositories, issue-following capabilities, and wikis. It is a complete DevOps platform that enables professionals to perform all the tasks in a project—from project planning and source code management to monitoring and security.
In this tutorial, I will explain how we can clone a project from GitLab in Eclipse.
Implementation Steps
Step 1– Go to GitLab and select the project which you want to clone. Click on the blue color “Clone” button then copy the hyperlink as shown in the image. You can either Clone with SSH or Clone with HTTPS.
Step 2 – Open Eclipse and go to “File > Import” in eclipse as shown in the image.
Step 3– A window will pop up in which select Git Folder. Under the Git folder, select the option – “Projects from Git(with smart import)”as shown in the image.
Click on the “NEXT” button.
Step 4 – A new window will pop up in which select the option – “Clone URI” as shown in the image.
Click on the “NEXT” button.
Step 5 – Another window will pop up in which you have to paste the“GitLab Repository URL” and also“GitLab UserID and Password” and click on the “Next” button.
URI – This is the URL that we have cloned from GitLab in Step 1. Host – gitlab.com Repository path – path of the project in GitLab (This is auto-populated after entering URI)
Authentication User – Username of GitLab Password – password of GitLab
Step 6 – Select master and select “When fetching a commit, also fetch its tags“.
Click on the “Next” button.
Step 7 – Select the “Folder directory” in which you want to import the repository.
Click on the “Finish” button.
Step 8 – We have successfully imported the GitLab Repository as shown in the below image.
Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!
The Page Object model is an object design pattern in Selenium. Web pages are represented as classes. The various elements on the page are defined as variables in the class. All possible user interactions can then be implemented as methods in the class.
Advantages of Page Object Model
Simplifies the process of adapting to changes in the UI. When page elements change due to a UI update, modifications are isolated to the page object class.
Page objects contain methods that represent user actions on a web page. These methods make the tests more readable and understandable.
Common code related to web pages is stored in page classes. This code is reused in tests. This approach results in the reduction of the code.
What is Cucumber?
Cucumber is one such open-source tool, which supports Behavior Driven Development(BDD). In simple words, Cucumber can be defined as a testing framework, driven by plain English. It serves as documentation, automated tests, and development aid – all in one.
Dependency List
Cucumber Java – 7.6.0
Cucumber JUnit4 – 7.6.0
Java 11
Maven – 3.8.6
Selenium – 4.3.0
JUnit – 4.13.2
Project Structure
Implementation Steps
Step 1- Download and Install Java
Cucumber and Selenium need Java to be installed on the system to run the tests. Click here to know How to install Java.
Step 2 – Download and setup Eclipse IDE on the system
The Eclipse IDE (integrated development environment) provides strong support for Java developers. Click here to know How to install Eclipse.
Step 3 – Setup Maven
To build a test framework, we need to add a number of dependencies to the project. Click here to know How to install Maven.
Step 4 – Install Cucumber Eclipse Plugin
The cucumber plugin is an Eclipse plugin that allows eclipse to understand the Gherkin syntax. When we are working with cucumber, we write the feature files that contain Feature, Scenario, Given, When, Then, And, and But. They also include Tags, Scenario Outline, and Examples. By default, eclipse doesn’t understand these keywords so it doesn’t show any syntax highlighter. Cucumber Eclipse Plugin highlights the keywords present in Feature File. Refer to this tutorial to get more detail – How to setup Cucumber with Eclipse.
Step 5 – Create a new Maven Project
To create a new Maven project, go to the File -> New Project-> Maven-> Maven project-> Next -> Enter Group ID & Artifact ID -> Finish.
Step 6 – Create source folder src/test/resources to create test scenarios in the Feature file
A new Maven Project is created with 2 folders – src/main/java and src/test/java. To create test scenarios, we need a new source folder called – src/test/resources. To create this folder, right-click on your maven project ->select New ->Java and then Source Folder.
Mention the source folder name as src/test/resources and click the Next button. This will create a source folder under your new Maven project as shown in the below image.
Step 7 – Add Selenium, JUnit4, and Cucumber dependencies to the project
Step 8 – Add Maven Compiler Plugin and Surefire Plugin
The compiler plugin is used to compile the source code of a Maven project. This plugin has two goals, which are already bound to specific phases of the default lifecycle:
Step 9 – Create a feature file in the src/test/resourcesdirectory
Create a folder with name features. Now, create the feature file in this folder. The feature file should be saved with extension .feature. This feature file contains the test scenarios created to test the application. The Test Scenarios are written in Gherkins language in the format of Given, When, Then, And, But.
Below is an example of Test Scenarios in the feature file. I have failed one test scenario intentionally – @MissingUsername.
Feature: Login to HRM Application
Background:
Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
@ValidCredentials
Scenario: Login with valid credentials
When User enters username as "Admin" and password as "admin123"
Then User should be able to login sucessfully and new page open
@InvalidCredentials
Scenario Outline: Login with invalid credentials
When User enters username as "<username>" and password as "<password>"
Then User should be able to see error message "<errorMessage>"
Examples:
| username | password | errorMessage |
| Admin | admin12$$ | Invalid credentials |
| admin$$ | admin123 | Invalid credentials |
| abc123 | xyz$$ | Invalid credentials |
@MissingUsername
Scenario Outline: Login with blank username
When User enters username as " " and password as "admin123"
Then User should be able to see a message "Required1" below Username
Step 10 – Create the classes for locators, actions, and utilities in src/main/java
Create a Java Class for each page where define WebElements as variables using Annotation @FindBy. Create another Java class that contains methods for actions performed on WebElements. Here, I’m going to create 2 classes for locators – LoginPageLocators and HomePageLocators.java as well as 2 classes for actions – LoginPageActions and HomePageActions
The Locator class contains WebElements which are identified by @FindBy annotation as shown below:-
Action class contains methods for the action to be performed on the web elements identified in the locator class as shown below:-
public void login(String strUserName, String strPassword) {
// Fill user name
this.setUserName(strUserName);
// Fill password
this.setPassword(strPassword);
// Click Login button
this.clickLogin();
}
}
The initElements is a static method of the PageFactory class that is used to initialize all the web elements located by @FindBy annotation. Only after the WebElements are initialized, they can be used in the methods to perform actions.
public Login(WebDriver driver) {
this.driver = driver;
// This initElements method will create all WebElements
PageFactory.initElements(driver, this);
}
Below is the sample code of the LoginPageLocators.
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class LoginPageLocators {
@FindBy(name = "username")
public WebElement userName;
@FindBy(name = "password")
public WebElement password;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[1]/div/span")
public WebElement missingUsernameErrorMessage;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
public WebElement login;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
public WebElement errorMessage;
}
Below is the sample code for the HomePageLocators.
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class HomePageLocators {
@FindBy(xpath = "//*[@id='app']/div[1]/div[2]/div[2]/div/div[1]/div[1]/div[1]/h5")
public WebElement homePageUserName;
}
Create the action classes for each web page. These action classes contain all the methods needed by the step definitions. In this case, I have created 2 action classes – LoginPageActions, HomePageActions
LoginPageActions
import org.openqa.selenium.support.PageFactory;
import com.example.locators.LoginPageLocators;
import com.example.utils.HelperClass;
public class LoginPageActions {
LoginPageLocators loginPageLocators = null;
public LoginPageActions() {
this.loginPageLocators = new LoginPageLocators();
PageFactory.initElements(HelperClass.getDriver(),loginPageLocators);
}
// Set user name in textbox
public void setUserName(String strUserName) {
loginPageLocators.userName.sendKeys(strUserName);
}
// Set password in password textbox
public void setPassword(String strPassword) {
loginPageLocators.password.sendKeys(strPassword);
}
// Click on login button
public void clickLogin() {
loginPageLocators.login.click();
}
// Get the error message when username is blank
public String getMissingUsernameText() {
return loginPageLocators.missingUsernameErrorMessage.getText();
}
// Get the Error Message
public String getErrorMessage() {
return loginPageLocators.errorMessage.getText();
}
public void login(String strUserName, String strPassword) {
// Fill user name
this.setUserName(strUserName);
// Fill password
this.setPassword(strPassword);
// Click Login button
this.clickLogin();
}
}
HomePageActions
import org.openqa.selenium.support.PageFactory;
import com.example.locators.HomePageLocators;
import com.example.utils.HelperClass;
public class HomePageActions {
HomePageLocators homePageLocators = null;
public HomePageActions() {
this.homePageLocators = new HomePageLocators();
PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
}
// Get the User name from Home Page
public String getHomePageText() {
return homePageLocators.homePageUserName.getText();
}
}
Create a Helper class where we are initializing the web driver. We are also initializing the web driver wait and defining the timeouts. A private constructor of the class is created. It will declare the web driver. Whenever we create an object of this class, a new web browser is invoked.
import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
public class HelperClass {
private static HelperClass helperClass;
private static WebDriver driver;
public final static int TIMEOUT = 10;
private HelperClass() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
driver.manage().window().maximize();
}
public static void openPage(String url) {
driver.get(url);
}
public static WebDriver getDriver() {
return driver;
}
public static void setUpDriver() {
if (helperClass==null) {
helperClass = new HelperClass();
}
}
public static void tearDown() {
if(driver!=null) {
driver.close();
driver.quit();
}
helperClass = null;
}
}
Step 11 – Create a Java Class called Definition in src/test/java
Create a Java Class called Definition where we will create the Test Code related to Given, When, Then of the Feature file in src/test/java
Now, we need to create the Step Definition of the Feature File – LoginPageDefinitions.java.
import org.junit.Assert;
import com.example.actions.ForgotPasswordActions;
import com.example.actions.HomePageActions;
import com.example.actions.LoginPageActions;
import com.example.utils.HelperClass;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class LoginPageDefinitions {
LoginPageActions objLogin = new LoginPageActions();
HomePageActions objHomePage = new HomePageActions();
@Given("User is on HRMLogin page {string}")
public void loginTest(String url) {
HelperClass.openPage(url);
}
@When("User enters username as {string} and password as {string}")
public void goToHomePage(String userName, String passWord) {
// login to application
objLogin.login(userName, passWord);
// go the next page
}
@Then("User should be able to login sucessfully and new page open")
public void verifyLogin() {
// Verify home page
Assert.assertTrue(objHomePage.getHomePageText().contains("Employee Information"));
}
@Then("User should be able to see error message {string}")
public void verifyErrorMessage(String expectedErrorMessage) {
// Verify home page
Assert.assertEquals(objLogin.getErrorMessage(),expectedErrorMessage);
}
@Then("User should be able to see a message {string} below Username")
public void verifyMissingUsernameMessage(String message) {
Assert.assertEquals(objLogin.getMissingUsernameText(),message);
}
}
Step 12 – Create a Hook class in src/test/java
Create the hook class that contains the Before and After hook to initialize the web browser and close the web browser. I have added the code to take the screenshot of the failed scenario in @After Hook.
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import com.example.utils.HelperClass;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
public class Hooks {
@Before
public static void setUp() {
HelperClass.setUpDriver();
}
@After
public static void tearDown(Scenario scenario) {
//validate if scenario has failed
if(scenario.isFailed()) {
final byte[] screenshot = ((TakesScreenshot) HelperClass.getDriver()).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", scenario.getName());
}
HelperClass.tearDown();
}
}
Step 13 – Create a JUnit Cucumber Runner classin the src/test/java directory
Cucumber needs a TestRunner class to run the feature files. It is suggested to create a folder with the name of the runner in the src/test/java directory. Then create the Cucumber TestRunner class in this folder. Below is the code of the Cucumber TestRunner class.
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
@RunWith(Cucumber.class)
@CucumberOptions(tags = "", features = "src/test/resources/features/LoginPage.feature", glue = "com.example.definitions",
plugin = {})
public class CucumberRunnerTests {
}
Note:- The name of the Runner class should end with Test otherwise we can’t run the tests using Command Line.
Step 14 – Run the tests from JUnit
You can execute the test script by right-clicking on TestRunner class -> Run As JUnit.
Step 15 – Run the tests from the Command Line
Run the below command in the command prompt to run the tests and to get the test execution report.
mvn clean test
The output of the above program is
Step 16 – Cucumber Report Generation
To get Cucumber Test Reports, add cucumber.properties under src/test/resources and add the below instruction in the file.
cucumber.publish.enabled=true
Below is the image of the Cucumber Report generated using Cucumber Service.
In the above example, as we can see, one of the tests has failed. So, when a test fails, we have written the code to take a screenshot of the failed step. The highlighted box above shows the image of the failed test. You can click on that to see the screenshot.
That’s it! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
MySQL is the most popular Open Source SQL database management system that is developed, distributed, and supported by Oracle Corporation. MySQL databases are relational. MySQL stores data in the form of tables that can be modified using Structured Query Language. MySQL Server works in client/server or embedded systems.
How to install MySQL on Windows?
Step 1 – Open the MySQL website on a browser. Click on the following link:
Choose the desired installer and click on download.
Step 2 – Select “No thanks. just start my download”.
Step 3 – After the download, open the installer.
Step 4 – It will ask for permission; when it does, click Yes. The installer will then open. Now, it will ask to choose the setup type. Here, select Custom option. Click the “Next” button.
Step 5 – Select latest options from MySQL Servers, MySQL Workbench, and MySQL Shell and move them to right column “Products To Be Installed” using the arrow. Click the “Next” button.
Step 6 – Once all the selected products are installed, click on the “Execute” button.
Step 7 – Once the products will be downloaded, click the “Next” button.
Step 8 – The products are “Ready to Install”. Click on the “Execute” button.
Step 9 – Once the installations are completed, click on the “Next” button.
Step 10 – Configure the product. Click on the “Next” button.
Step 11 – Under Type and Networking, go with the default settings. Click on the “Next” button.
Step 12 – For authentication, use the recommended strong password encryption.
Step 13 – Set your MySQL Root password and click on the “Next” button.
Step 14 – Go for the default windows service settings. Click on the “Next” button.
Step 15 – Select the default option for Server File Permissions. Click on the “Next” button.
Step 16 – Under apply configuration, click on the “Execute” button.
Step 17 – Once the configuration is complete, click on the “Finish” button.
Step 18 – This screen shows that the Product Configuration is completed.
Step 19 – Complete the installation. This will now launch the MySQL Workbench and the MySQL Shell.
Step 20 – Once MySQL Workbench is installed, select the Local instance and enter the password.
Once MySQL has been successfully installed, the base tables have been initialized, and the server has been started, you can verify its working via some simple tests.
Open your MySQL Command Line Client; it should have appeared with a mysql> prompt. If you have set any password, write your password here. Now, you are connected to the MySQL server, and you can execute all the SQL command at mysql> prompt as follows:
Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!
I have created a lot of tutorials on creating Test Frameworks by integrating JUnit4 with Selenium, Cucumber, Serenity, Rest API, Springboot. This tutorial explain the steps to Integrate Cucumber7 with JUnit5.
JUnit 5 is composed of several different modules from three different sub-projects.
Cucumber and Selenium need Java to be installed on the system to run the tests. Click here to know How to install Java.
Step 2 – Download and setup Eclipse IDE on the system
The Eclipse IDE (integrated development environment) provides strong support for Java developers, which is needed to write Java code. Click here to know How to install Eclipse.
Step 3 – Setup Maven
To build a test framework, we need to add a number of dependencies to the project. It is a very tedious and cumbersome process to add each dependency manually. So, to overcome this problem, we use a build management tool. Maven is a build management tool that is used to define project structure, dependencies, build, and test management. Click here to know How to install Maven.
The Cucumber Eclipse plugin is a plugin that allows eclipse to understand the Gherkin syntax. The Cucumber Eclipse Plugin highlights the keywords present in Feature File. Click here to know more – Install Cucumber Eclipse Plugin.
Step 7 – Create a feature file in src/test/resources
Below is a sample feature file. Feature file should be saved as an extension of .feature. Add the test scenarios in this feature file. I have added sample test scenarios. The test scenarios are written in Gherkins language.
LoginPage.feature
@LoginPage
Feature: Login to HRM Application
Background:
Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
@ValidCredentials
Scenario: Login with valid credentials
When User enters username as "Admin" and password as "admin123"
Then User should be able to login successfully and new page open
@InvalidCredentials
Scenario Outline: Login with invalid credentials
When User enters username as "<username>" and password as "<password>"
Then User should be able to see error message "<errorMessage>"
Examples:
| username | password | errorMessage |
| Admin | admin12$$ | Invalid credentials |
| admin$$ | admin123 | Invalid credentials |
| abc123 | xyz$$ | Invalid credentials |
@FaceBookLink
Scenario: Verify FaceBook Icon on Login Page
Then User should be able to see FaceBook Icon
@LinkedInLink
Scenario: Verify LinkedIn Icon on Login Page
Then User should be able to see LinkedIn Icon
ForgetPasswordPage.feature
@ForgetPassword
Feature: Login to ForgotPassword Page
Background:
Given User is on HRMLogin page "https://opensource-demo.orangehrmlive.com/"
@ForgetPasswordLink
Scenario: Verify ForgetPassword link on Login Page
When User clicks on Forgot your Password Link
Then User should navigate to a new page
Step 8 – Create cucumber.properties file in src/test/resources
We need to create the junit-platform.properties file in the src/test/resources folder. Using a property file for reporting is quite helpful if you want to define several different properties.
cucumber.publish.enabled=true
Step 9 – Create a Helper class in src/main/java
We have used Page Object Model with Cucumber and TestNG. Create a Helper class where we are initializing the web driver, initializing the web driver wait, defining the timeouts, and creating a private constructor of the class, it will declare the web driver, so whenever we create an object of this class, a new web browser is invoked.
import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.chrome.ChromeOptions;
public class HelperClass {
private static HelperClass helperClass;
private static WebDriver driver;
public final static int TIMEOUT = 5;
private HelperClass() {
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
driver = new ChromeDriver(options);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(TIMEOUT));
}
public static void openPage(String url) {
driver.get(url);
}
public static WebDriver getDriver() {
return driver;
}
public static void setUpDriver() {
if (helperClass==null) {
helperClass = new HelperClass();
}
}
public static void tearDown() {
if(driver!=null) {
driver.quit();
}
helperClass = null;
}
}
Step 10 – Create Locator classes in src/main/java
Create a locator class for each page that contains the detail of the locators of all the web elements. Here, I’m creating 3 locator classes – LoginPageLocators, HomePageLocators,and ForgotPasswordLocators.
LoginPageLocators
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class LoginPageLocators {
@FindBy(name = "username")
public WebElement userName;
@FindBy(name = "password")
public WebElement password;
@FindBy(id = "logInPanelHeading")
public WebElement titleText;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[3]/button")
public WebElement login;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/div/div[1]/div[1]/p")
public WebElement errorMessage;
@FindBy(xpath = "//*[@href='https://www.linkedin.com/company/orangehrm/mycompany/']")
public WebElement linkedInIcon;
@FindBy(xpath = "//*[@href='https://www.facebook.com/OrangeHRM/']")
public WebElement faceBookIcon;
@FindBy(xpath = "//*[@id='app']/div[1]/div/div[1]/div/div[2]/div[2]/form/div[4]/p")
public WebElement ForgotYourPasswordLink;
}
HomePageLocators
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class HomePageLocators {
@FindBy(xpath = "//*[@id='app']/div[1]/div[2]/div[2]/div/div[1]/div[1]/div[1]/h5")
public WebElement homePageUserName;
}
ForgotPasswordLocators
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class ForgotPasswordLocators {
@FindBy(xpath = "//*[@id='app']/div[1]/div[1]/div/form/h6")
public WebElement ForgotPasswordHeading;
}
Step 11 – Create Action classes in src/main/java
Create the action classes for each web page. These action classes contain all the methods needed by the step definitions. In this case, I have created 2 action classes – LoginPageActions, HomePageActions, and ForgotPasswordActions.
LoginPageActions
In this class, the very first thing will do is to create the object of the LoginPageLocators class so that we should be able to access all the PageFactory elements. Secondly, create a public constructor of LoginPageActions class.
import org.openqa.selenium.support.PageFactory;
import com.example.locators.LoginPageLocators;
import com.example.utils.HelperClass;
public class LoginPageActions {
LoginPageLocators loginPageLocators = null;
public LoginPageActions() {
this.loginPageLocators = new LoginPageLocators();
PageFactory.initElements(HelperClass.getDriver(),loginPageLocators);
}
// Set user name in textbox
public void setUserName(String strUserName) {
loginPageLocators.userName.sendKeys(strUserName);
}
// Set password in password textbox
public void setPassword(String strPassword) {
loginPageLocators.password.sendKeys(strPassword);
}
// Click on login button
public void clickLogin() {
loginPageLocators.login.click();
}
// Get the title of Login Page
public String getLoginTitle() {
return loginPageLocators.titleText.getText();
}
// Get the title of Login Page
public String getErrorMessage() {
return loginPageLocators.errorMessage.getText();
}
// LinkedIn Icon is displayed
public Boolean getLinkedInIcon() {
return loginPageLocators.linkedInIcon.isDisplayed();
}
// FaceBook Icon is displayed
public Boolean getFaceBookIcon() {
return loginPageLocators.faceBookIcon.isDisplayed();
}
// Click on Forget Your Password link
public void clickOnForgetYourPasswordLink() {
loginPageLocators.ForgotYourPasswordLink.click();
}
public void login(String strUserName, String strPassword) {
// Fill user name
this.setUserName(strUserName);
// Fill password
this.setPassword(strPassword);
// Click Login button
this.clickLogin();
}
}
HomePageActions
import org.openqa.selenium.support.PageFactory;
import com.example.locators.HomePageLocators;
import com.example.utils.HelperClass;
public class HomePageActions {
HomePageLocators homePageLocators = null;
public HomePageActions() {
this.homePageLocators = new HomePageLocators();
PageFactory.initElements(HelperClass.getDriver(),homePageLocators);
}
// Get the User name from Home Page
public String getHomePageText() {
return homePageLocators.homePageUserName.getText();
}
}
ForgotPasswordActions
import org.openqa.selenium.support.PageFactory;
import com.example.locators.ForgotPasswordLocators;
import com.example.utils.HelperClass;
public class ForgotPasswordActions {
ForgotPasswordLocators forgotPasswordLocators = null;
public ForgotPasswordActions() {
this.forgotPasswordLocators = new ForgotPasswordLocators();
PageFactory.initElements(HelperClass.getDriver(),forgotPasswordLocators);
}
// Get the Heading of Forgot Password page
public String getForgotPasswordPageText() {
return forgotPasswordLocators.ForgotPasswordHeading.getText();
}
}
Step 12 – Create a Step Definition file in src/test/java
Create the corresponding Step Definition file of the feature file.
LoginPageDefinitions
import org.junit.jupiter.api.Assertions;
import com.example.actions.ForgotPasswordActions;
import com.example.actions.HomePageActions;
import com.example.actions.LoginPageActions;
import com.example.utils.HelperClass;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class LoginPageDefinitions{
LoginPageActions objLogin = new LoginPageActions();
HomePageActions objHomePage = new HomePageActions();
ForgotPasswordActions objForgotPasswordPage = new ForgotPasswordActions();
@Given("User is on HRMLogin page {string}")
public void loginTest(String url) {
HelperClass.openPage(url);
}
@When("User enters username as {string} and password as {string}")
public void goToHomePage(String userName, String passWord) {
// login to application
objLogin.login(userName, passWord);
// go the next page
}
@When("User clicks on Forgot your Password Link")
public void goToForgotYourPasswordPage() {
objLogin.clickOnForgetYourPasswordLink();
}
@Then("User should be able to login sucessfully and new page open")
public void verifyLogin() {
// Verify home page
Assertions.assertTrue(objHomePage.getHomePageText().contains("Employee Information"));
}
@Then("User should be able to see error message {string}")
public void verifyErrorMessage(String expectedErrorMessage) {
// Verify home page
Assertions.assertEquals(objLogin.getErrorMessage(),expectedErrorMessage);
}
@Then("User should be able to see LinkedIn Icon")
public void verifyLinkedInIcon( ) {
Assertions.assertTrue(objLogin.getLinkedInIcon());
}
@Then("User should be able to see FaceBook Icon")
public void verifyFaceBookIcon( ) {
Assertions.assertTrue(objLogin.getFaceBookIcon());
}
@Then("User should navigate to a new page")
public void verfiyForgetYourPasswordPage() {
Assertions.assertEquals(objForgotPasswordPage.getForgotPasswordPageText(), "Reset Password");
}
}
Step 13 – Create Hook class in src/test/java
Create the hook class that contains the Before and After hook to initialize the web browser and close the web browser.
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import com.example.utils.HelperClass;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.Scenario;
public class Hooks {
@Before
public static void setUp() {
HelperClass.setUpDriver();
}
@After
public static void tearDown(Scenario scenario) {
//validate if scenario has failed
if(scenario.isFailed()) {
final byte[] screenshot = ((TakesScreenshot) HelperClass.getDriver()).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", scenario.getName());
}
HelperClass.tearDown();
}
}
Step 14 – Create a Cucumber Test Runner class in src/test/java
Cucumber needs a TestRunner class to run the feature files. It is suggested to create a folder with the name of the runner in the src/test/java directory and create the Cucumber TestRunner class in this folder. Below is the code of the Cucumber TestRunner class.
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("com.example")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example")
public class CucumberRunnerTests {
}
Step 15 – Run the tests from Maven or Command Line
Use the below command to run the tests.
mvn clean verify
Step 16 – Cucumber Report Generation
Below is the image of the Cucumber Report generated using the Cucumber Service.
Serenity BDD is an open-source library that aims to make the idea of living documentation a reality.
What is Rest Assured?
Rest Assured is one of the most powerful libraries for testing RESTful API using Java language. Rest-Assured is a Java-based library that is used to test RESTful Web Services. This library behaves like a headless Client to access REST web services. The Rest-Assured library also provides the ability to validate the HTTP Responses received from the server. For e.g. we can verify the Status code, Status message, Headers, and even the Body of the response. This makes Rest-Assured a very flexible library that can be used for testing. In this post, we will learn how to write high-quality, expressive REST API tests using Rest Assured and Serenity BDD.
Prerequisite
Java 17 installed
Maven installed
Eclipse or IntelliJ installed
Dependency List:
Java 17
Maven – 3.9.5
Serenity – 4.0.18
Serenity Rest Assured – 4.0.18
Serenity Cucumber – 4.0.18
Rest Assured – 5.3.2
JUnit – 4.13.2
Maven Surefire Plugin – 3.2.1
Maven Failsafe Plugin – 3.2.1
Maven Compiler Plugin – 3.11.0
Project Structure
Implementation Steps
Step 1 – Update Properties section in Maven pom.xml
Step 4 – Create a Feature filein src/test/resources
Create a features folder within src/test/resources to create test scenarios in the Feature file. Test Scenarios are created in a Feature File which contains an overall description of a feature as well as a number of scenarios. Feature files can be placed in different locations, but you can reduce the amount of configuration you need to do with serenity if you put them in the src/test/resources/features directory. In this feature file, will send a request, and the response should be of status “200” and employee name of “Tiger Nixon”. The feature file looks something like this:
Feature: Employee Details
@GetEmployee
Scenario: Get the details of employee
Given I send a request to endpoint
Then the API should return status 200
And Response should contains employee name "Tiger Nixon"
Step 5 – Create the Step Definition class or Glue Code
To use Rest-assured, Serenity provides class SerenityRest
import net.serenitybdd.rest.SerenityRest;
It is a Java method with an expression that is used to link it to Gherkin steps. When Cucumber executes a Gherkin step, it will look for a matching step definition to execute. These use annotations like @given, @when, and @then to match lines in the scenario to java methods
package org.example.definitions;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.restassured.response.Response;
import net.serenitybdd.rest.SerenityRest;
import static org.hamcrest.Matchers.equalTo;
public class EmployeeDefinitions {
private static final String URL = "http://dummy.restapiexample.com/api/v1/employee/1";
public Response response;
@Given("I send a request to endpoint")
public void sendRequest() {
response = SerenityRest.given().contentType("application/json").header("Content-Type", "application/json")
.when().get(URL);
}
@Then("the API should return status {int}")
public void verifyResponse(int status) {
SerenityRest.restAssuredThat(response -> response.statusCode(status));
}
@And("Response should contains employee name {string}")
public void verifyResponseContent(String expectedEmployeeName) {
SerenityRest.restAssuredThat(response -> response.body("data.employee_name", equalTo(expectedEmployeeName)));
}
}
Step 6 – Create Serenity Test Runner
Cucumber runs the feature files via JUnit and needs a dedicated Test Runner class to run the feature files. When you run the tests with serenity, you use the CucumberWithSerenity test runner. If the feature files are not in the same package as the test runner class, you also need to use the@CucumberOptionsclass to provide the root directory where the feature files can be found. It is the starting point for JUnit to start executing the tests. TestRunner class is created undersrc/test/java. The test runner to run all of the feature files looks like this:
import org.junit.runner.RunWith;
import io.cucumber.junit.CucumberOptions;
import net.serenitybdd.cucumber.CucumberWithSerenity;
@RunWith(CucumberWithSerenity.class)
@CucumberOptions(plugin = { "pretty" }, features = "src/test/resources/features/Employee.feature", glue = {
"org.example.definitions" })
public class SerenityAPITestRunner {
}
Step 7 – Create serenity.properties file
Serenity.properties file is created at the root level.
serenity.project.name = Rest API Testing using Serenity, Cucumber and JUnit4
Step 8 – Serenity Tests Execution
You can run the tests from SerenityAPITestRunner or from the command line by
mvn clean verify
Test Execution Page looks like this as shown below image
Step 9 – Verify the Serenity Reports
A number of reports are generated, but we are concerned about index.html and serenity-summary.html.
The report is well-formatted and contains consolidated results. Reporting is one of the major pillars of Serenity. Serenity Report not only reports on whether a test scenario passes or fails but documents what it did, in a step-by-step narrative format. The below pic illustrates the test results for our first acceptance criteria:
The test report generated by Serenity is placed under target/site/serenity/index.html.
Index.html
The first tab is called “Overall Test Results” and it provides information about test statistics. This Overall Test Result shows the Scenario Results (No Of Test Cases Pass, No Of Test Cases Failed, No of Test Cases Pending, No Of Test Cases Ignored, No Of Test Cases Skipped).
In the below pic, the report shows the test scenario steps status and time taken for each step to execute.
With the use of the REST Query button, it’s possible to display query details. Visible details:
There is also the “Requirements” tab. When we have tests as part of our code base, all test results will be organized as associated with requirements.
There is also a “Features” tab. This page lists all the features that are part of your suite. If you expand that row you’ll see the bit of narrative text that is part of the current feature file.
Serenity-Summary.html
We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!
In this tutorial, we will convert a Java list into a JSON Object. Most of the times, the JSONs built in the organizations are complex. It contains string, int, list, arrays and soon.
In this tutorial, we will use the below mentioned dependency.
Jenkins is a self-contained, open-source automation server that can be used to automate all sorts of tasks related to building, testing, and delivering or deploying software.
Jenkins can be installed through native system packages, Docker, or even run standalone by any machine with a Java Runtime Environment (JRE) installed.