Mastering QA

Android Studio

android-studio

Official Docs 

Explore the latest tools and features for Android development on the Official Android Studio website. Stay updated with the most powerful integrated development environment (IDE) designed specifically for building  & testing high-quality Android apps!
Become a Pro Member - Unlock Advanced Tools & Resources

Gain exclusive access to test apps and automation frameworks designed to elevate your QA skills. Become a Pro Member!

Frameworks

Accelerate your testing with our premium Android UI Test Framework. Gain the tools you need to automate, optimize, and perfect your app’s user experience with ease.

Introduction to Android Studio

android-studio

Introduction to Android Studio

Welcome to Mastering QA! In this guide, we’ll start by introducing you to Android Studio, the official Integrated Development Environment (IDE) for Android app development. Whether you’re a beginner or an advanced user, understanding Android Studio is crucial for building and testing Android applications.

What is Android Studio?

Android Studio is the official IDE for Android app development, based on IntelliJ IDEA. It provides a comprehensive set of tools for developing and debugging Android applications, including a robust code editor, emulator, and more.

Key Features

Here are some features of Android Studio:

  • Intelligent Code Editor: Offers code completion, refactoring, and analysis.
  • Visual Layout Editor: Design your app visually with drag-and-drop functionality.
  • Flexible Build System: Powered by Gradle, it allows for custom build configurations.
  • Real-time Profiler: Monitor your app's CPU, memory, and network activity in real-time.

How To Install Android Studio

To begin the installation process for Android Studio, first, proceed to the official website by selecting this link: Download Android Studio. As of the creation of this document, the most current version of Android Studio is Hedgehog To download this version, click on the Download Android Studio Hedgehog button. Doing so will direct you to the Terms and Conditions page.

android-studio-download
Android Studio - Hedgehog Version
Carefully examine the details outlined in the Terms and Conditions and ensure to mark the checkbox indicating your acknowledgment and agreement with the stated terms. Depending on the specific chip architecture of your Mac, select the appropriate download option to initiate the download of the Integrated Development Environment (IDE). For instance, as I am utilizing a Mac equipped with an Apple chip, I will proceed by selecting the corresponding option designated for Apple silicon
android-studio-terms
Choose A Download Version Compatible For Your Machine

Select a destination for the file to be saved, and upon completion, the file will be located in your designated folder. To initiate the installation process of Android Studio, double-click the file. This action will launch the Android Studio Installer. Proceed by dragging the application into the Applications folder, ensuring it is accessible from the Launchpad for your convenience.

android-studio-installation-downloads
Find The DMG File & Add It to Your Applications Folder

After transferring the Android Studio application to the Applications folder, proceed to double-click the Android Studio icon. You will then be prompted by Apple to verify trust for the application. Upon confirmation, Android Studio will initiate, first presenting tips for optimal usage, followed by the Welcome screen to begin your development journey.

welcome-to-android-studio-screen
Android Studio Welcome Screen

Configuring The SDK

To configure the SDK on a Mac, ensure that the Android Studio application is active and in the foreground. Next, navigate to the top left corner of your screen, click on Android Studio, and from the dropdown menu, select Settings…

settings-android-studio
Navigating to the Settings Screen in Android Studio

Upon accessing the Settings screen, please proceed to the Languages and Frameworks section.

settings-screen-android-studio
Languages & Frameworks via the Settings

Please proceed to expand the dropdown menu in order to access the Android SDK Settings. Should you encounter a notification indicating “The Android SDK location cannot be at the file system root” kindly select the Edit option to proceed to SDK Components Setup screen.

settings-sdk-android-studio
Android SDK & Add The SDK Path
settings-sdk-edit-android-studio
Installing The Android SDK Platform

In this scenario, the screen indicates the presence of an existing Android SDK, which is beneficial. Please proceed by clicking Next

Following this, we will be directed to the Verify Settings screen for further confirmation.

settings-sdk-edit-next-android-studio
Verify Settings Screen

Given that Android Studio has already identified the SDK’s location, we may proceed by selecting Next to advance further in the process.

settings-sdk-edit-next-finish-android-studio
Click Finish To Complete The SDK Setup

Since that the SDK is already up to date, we may proceed by selecting Finish This action will redirect us back to the SDK Tools and Platforms screen.

settings-sdk-2-android-studio
View The Different Android Platform Versions Available to Download

Next, we will select and download various Android platforms, which will be essential for building an Android emulator later on. Below, you will find a comprehensive list of Android versions, allowing you to precisely choose the version you wish to utilize for your application’s development.

android-studio-choosing-sdk
A Comprehensive List of Android Versions

I have opted to select Android Studio version 13.0, corresponding to API version 34. Adjacent to this option, a download icon is displayed, signifying that this specific version will be downloaded.

android-studio-choosing-sdk-4
Select Android Studio Version 13.0

Subsequently, proceed to select the SDK Tools tab, then carefully choose all the components listed in Step 2 below. Once completed, click on Apply to proceed with the installation.

android-studio-choosing-sdk-tools
Click Apply To Download The Version

A confirmation screen will be displayed, enumerating all selected Android platforms and SDK Tools. Please click OK to initiate the download process.

android-studio-sdk-confirmation
Confirm Changes & Click Ok

Upon completing all necessary steps, please click on Finish to conclude the process.

android-studio-sdk-installed
Android SDK Component Setup Is Complete

 

After completing this step, you will be redirected to the Android SDK screen. Please proceed by simply clicking OK To verify that all processes have executed as expected, it is recommended that you close and then reopen Android Studio. This measure ensures the smooth integration of any changes.

Conclusion

Android Studio is a powerful tool that lays the foundation for Android development. In the next guide, we’ll walk you through setting up your first Android emulator, a crucial step for testing your applications. Continue to Setting Up Your First Android Emulator to learn more.

Setting Up Your First Android Emulator

android-studio

In the previous guide, we introduced you to Android Studio. Now, let’s move forward by setting up your first Android emulator. Emulators are essential for testing your applications without needing a physical device.

What is an Android Emulator?

An Android emulator is a virtual device that mimics the hardware and software of a real Android device. It allows you to test your applications on various configurations and Android versions.

Open Android Studio

First things first, let’s make sure Android Studio is up and running on your Mac.

android-launch-open
Android Studio Hedgehog Launched

Launch the Virtual Device Manager

Now that Android Studio is up and running, there are a couple ways you can create or launch a virtual device. Pick a method that best fits your current setup.

Welcome Screen

On the welcome screen click More Actions Virtual Device Manager

android-welcome-screen-create-virtual-device
Android Studio Welcome Screen > Create Virtual Device

Project View

In project view, navigate to the menu bar and click on Tools Device Manager .

android-launch-via-tools
Android Studio - Device Manager

Creating a New Virtual Device

Now that the AVD Manager is launched, you may see a list of existing virtual devices, if others were previously created. To create a new one, click on the +  button to create a virtual device.

android-create-virtual-device
Android Studio - Creating A New Virtual Device

Choose a Device Definition

Next on the Select Hardware screen, you can choose the type device you want to emulate. If you’re not sure about which one to build, you can’t go wrong with a Pixel. In this example I’m going to choose the Pixel 7 and then click  Next .

android-choose your-virtual-device
Creating A New Virtual Device

Select a System Image

Next, you’ll need to choose a system image. This is essentially the version of Android you want to run on your virtual device. Pick the latest version available, or select an older version if your app requires it. If the version you want to use is grayed out, click the download icon to download that version.

android-choose api-version-device
Choosing A Device Type

Configure Your Virtual Device

Now it’s time to configure your virtual device. For your AVD Name, you can choose to keep the default name but better command line readability, use this style pixel-7-api-34. Ensure the startup orientation is in Portrait and check the box to Enable device frame.

android-verify-device
Selecting A System Image

Finish and Launch

Once you’ve configured your virtual device to your liking, click on the Finish button. Android Studio will then create your virtual device. Once it’s done, click on the play button to launch your emulator.

android-new-virtual-device
New Virtual Device Created

Emulator Running

Depending on your Mac’s performance, it might take a little while for the emulator to start up.

android-launch-new-virtual-device
Pixel 7 Emulator Launched

Conclusion

With your emulator set up, you can now test your applications in a virtual environment. The next step involves installing APK apps on your emulator for testing purposes. Proceed to Installing an APK app on an Android Emulator to continue your journey.

Installing an APK app on an Android Emulator

android-studio

After setting up your Android emulator, the next step is to install and test APK applications on it. This guide will walk you through the process of installing an APK on your emulator.

Installing App via Project View

With your emulator up and running, it’s time to fire up your app! Go back to Android Studio and click on the green play button in the toolbar or from the menu bar, select Run . Android Studio will build your app and install it on the emulator.

android-studio-click-play-to-build-app
Installing App On Emulator

Once the installation process is complete, your app will automatically launch on the emulator.

android-studio-app-build-from-project
App Installed Successfully

Installing Your App via APK

Another method to installing an app on your emulator would be through an apk file. To add an apk to your device simply navigate to location of your apk or download an apk file from a trusted source online. For this example I will be using the same apk generated after building the app from the project. Since I’m using Flutter project to build this app, the location of the apk is here App Project build app outputsflutter-apkapp-debug.apk

android-studio-locating-apk-file
Build Location of the APK File

Once you locate your apk, simply drag and drop the apk onto the emulator for it to install. 

installing-apk-on-emulator
Installing APK By Dragging & Dropping On Emulator

Conclusion

Voila! Your app is now running on the emulator. Take some time to explore its features and functionalities. Click around, interact with different elements, and get a feel for how it behaves. Next, we’ll explore how to use ADB with Android emulators to perform various debugging tasks. Head over to Using ADB with Android Emulators for more insights.

Using ADB with Android Emulators

android-studio

Previously, we covered installing APK apps on your emulator. Now, let’s delve into using ADB (Android Debug Bridge) with Android emulators. ADB is a powerful command-line tool that enables communication with your emulator or device.

Want Access to the Test App & Framework?

Unlock access to our test app crafted to provide a hands-on approach to Android UI testing. 

Tip: Please ensure you have an emulator created and running before hand.

device-info-pixel-8-api-33
Device Info: Pixel 8 | API 33

Connecting ADB to an Emulator

Once your emulator is running, you need to connect ADB to it.

Open Terminal: Launch the Terminal App on your on your Mac.

android-studio-launch-terminal
Launch Terminal

Navigate to ADB Directory: Navigate to the directory where ADB is installed. This is typically in the platform-tools directory of your Android SDK.

bash
cd /Users/{UserName}/Library/Android/sdk/platform-tools
terminal-platform-tools
Changing Directory To Platform Tools

Check Connected Devices: Run the following command to list connected devices and emulators.

bash
adb devices
terminal-platform-tools-adb-devices-found
List of Running Devices Displayed
You should see your emulator listed. If not, restart the ADB server. In Terminal paste the command below:
bash
adb kill-server
adb start-server

Common ADB Commands

Here are some essential ADB commands for quality testing:

  • Installing an APK: To Install an application on the emulator. Use this command.
bash
adb install /Users/{UserName}/Desktop/test-apps/app-debug.apk
adb-install-apk
Installing An APK Using ADB Command
  • Get Android Package Name: Get the name of the Android app’s package name in order to use the uninstall command later. With the test app lauched on the emulator, open a new terminal and enter this command below:
bash
adb shell dumpsys window | grep 'mCurrentFocus'
name-of-app-package-and-main-activity
Name of App Package & Main Activity
  • Uninstall an APK: Remove an application from the emulator.
bash
adb uninstall com.example.yourapp
adb-uninstall-app
Uninstalling APK Using ADB Command

Conclusion

The ADB is an essential tool for Android development and debugging. Mastering its commands will enhance your ability to manage and debug your applications effectively. Up next, we’ll cover automating UI tests on Android emulators, a crucial step for ensuring your app’s usability. Continue to Automating UI Tests on Android Emulators for detailed instructions.

Automating UI Tests on Android Emulators

android-studio

Building on our knowledge of ADB, this guide focuses on automating UI tests on Android emulators. Automated UI tests ensure that your application’s user interface behaves as expected across different scenarios and devices.

Why Automate UI Tests?

Automated UI tests save time and resources by running tests that simulate user interactions. They help identify bugs and inconsistencies in the UI, providing a reliable way to maintain high-quality applications.

Setting Up Espresso for UI Testing

Add Dependencies

You need to add Espresso and other related dependencies in your build.gradle file of your Android app module (app/build.gradle).

android/app/build.gradle
 defaultConfig {
     testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 }

Create a Test Class

 In src/androidTest/java and call it MainActivityTest.

This test will ensure that the app is launched and ready for interaction. The test method will simulate a user clicking the plus button and verifies the resulting UI state.

MainActivityTest.class
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTest {
  • @RunWith(AndroidJUnit4.class): This annotation tells JUnit to run the test class using the AndroidJUnit4 test runner. This runner provides compatibility with Android components and manages the test lifecycle.
  • @LargeTest: This annotation classifies the test as a “large” test. Large tests typically involve integration testing, where multiple components of the application are tested together.
MainActivity.class
@Rule
public ActivityScenarioRule<MainActivity> activityRule =
        new ActivityScenarioRule<>(MainActivity.class);

@Rule
public DisableAnimationsRule disableAnimationsRule = new DisableAnimationsRule();
  • @Rule: Rules in JUnit are used to add or extend the behavior of each test method in a test class. They provide additional functionality before and after each test is run.
  • ActivityScenarioRule<MainActivity> activityRule: This rule launches the specified activity (MainActivity in this case) before each test and closes it after each test. It provides a simplified way to test activities. The ActivityScenarioRule starts and stops the activity and also ensures that the activity is running before the test begins.
  • DisableAnimationsRule disableAnimationsRule: This custom rule is used to disable system animations during the test run. Animations can interfere with Espresso tests by causing unexpected delays or timing issues, so disabling them ensures more consistent test results.
MainActivity.class
@Test
public void testClickPlusButton() throws InterruptedException {
    // Click the plus button to open the AddEditTaskActivity
    onView(withId(R.id.fab)).perform(click());

    // Verify that the AddEditTaskActivity is displayed by checking for the presence of the title EditText
    onView(withId(R.id.titleEditText)).check(matches(withText("")));
}
  • @Test: This annotation indicates that the following method is a test method. JUnit will execute this method as a test case.
  • public void testClickPlusButton(): This is the test method. The method name typically describes what is being tested. In this case, it tests the behavior of clicking the plus button.
  • onView(withId(R.id.fab)).perform(click());: This line uses Espresso to interact with the UI. It finds a view with the ID fab which is the floating action button in this app and performs a click action on it. Espresso’s onView method is used to find views in the current activity’s layout, and perform is used to execute actions on those views.
  • onView(withId(R.id.titleEditText)).check(matches(withText("")));: This line verifies that a view with the ID titleEditText is displayed and that its text is empty. This check is used to confirm that the AddEditTaskActivity is displayed by looking for the presence of an empty title EditText. The check method is used to perform assertions on views, and matches verifies that the view’s state matches the specified condition. 
Since this is a ToDo app, let’s enhance the test suite by adding two more critical scenarios: one for adding a task and another for deleting a task. These scenarios will ensure that the core functionalities of creating and removing tasks are working as expected.
MainActivity.class
@Test
public void testAddTask() throws InterruptedException {
    // Click the plus button to open the AddEditTaskActivity
    onView(withId(R.id.fab)).perform(click());
    // Enter text into the title and description fields and close the keyboard
    onView(withId(R.id.titleEditText))
        .perform(typeText("New Task Title"), closeSoftKeyboard());
    onView(withId(R.id.descriptionEditText))
        .perform(typeText("New Task Description"), closeSoftKeyboard());

    // Click the save button
    onView(withId(R.id.saveButton)).perform(click());

    // Verify that the new task is displayed
    onView(withText(endsWith("New Task Title")))
        .check(matches(isDisplayed()));

}

@Test
public void testDeleteTask() throws InterruptedException {
    // Delete the task
    onView(withId(R.id.doneButton)).perform(click());
    Thread.sleep(2000);
    // Verify that the task is deleted by checking that the item is not in the list
    onView(withText(endsWith("Task to Delete"))).check(doesNotExist());
    Thread.sleep(2000);
}

Running UI Tests

Click on the green play icon next to the class definition to run all tests in the class. Alternatively, click on the green play icon next to individual test methods to run specific tests.

running-android-ui-test
Running Android UI Test

Viewing Test Results

  • Once the tests start running, the Run window will display the progress and results.
  • The Run window shows which tests passed or failed, along with detailed logs and stack traces for any failures.

Analyze Test Results

  • Green checkmarks indicate passed tests.
  • Red X marks indicate failed tests, with details about the failure.
  • Yellow warning signs indicate ignored or skipped tests.
reviewing-expresso-test-results
Reviewing Expresso Test Results

Conclusion

Automating UI tests with Espresso provides a robust way to ensure your app’s user interface functions correctly. Next, we’ll explore performance testing on Android emulators, which is vital for optimizing your app’s performance. Proceed to Performance Testing on Android Emulators for more information.

Performance Testing on Android Emulators

android-studio

Having covered UI testing, we now turn to performance testing on Android emulators. Performance testing helps identify bottlenecks and ensures your application runs smoothly under various conditions.

Performance Testing

Performance testing is crucial for delivering a responsive and efficient app. It helps detect issues related to memory usage, CPU load, and network performance, ensuring a seamless user experience.

Using Android Profiler

  • Open Android Profiler - In Android Studio, navigate to:
    View > Tool Windows > Profiler or you can click the Profiler icon in the bottom toolbar.
android-studio-profiler
Android Studio Profiler
  • Select an Emulator: Choose the emulator or device to profile. If your device is already running, it will automatically use that device.
android-studio-profiler-select-active-emulator
Android Studio Profiler > Select Active Emulator
  • CPU Profiler: Monitor your app's CPU usage, threads, and methods.
android-studio-cpu-profiler
Android Studio Profiler > CPU Profiler
  • Memory Profiler: Track memory allocation and garbage collection.
android-studio-memory-profiler
Android Studio Profiler > Memory Profiler

Running Performance Tests

  • Profile Your App: Use the profiler tools to identify performance issues during test execution.

Memory Profiler Record

android-studio-memory-profiler-record
Android Studio > Memory Profiler Record
android-studio-memory-profiler-results
Android Studio > Memory Profiler Results

CPU Profiler Record

android-studio-cpu-profiler-record
Android Studio > CPU Profiler Record
android-studio-cpu-profiler-results
Android Studio > CPU Profiler Results

Conclusion

Performance testing on Android emulators is essential for optimizing your app and ensuring it performs well under various conditions. This completes our series of guides on mastering Android Studio and emulators. Keep exploring and honing your skills to become a proficient Android developer and QA tester.

Appium

appium-featured-image

Official Docs

Discover more about Appium, the powerful tool for automating mobile app testing, by visiting the Official Appium Website. Explore its full range of features, documentation, and community resources to enhance your testing efficiency.

Become a Pro Member - Unlock Advanced Tools & Resources

Gain exclusive access to test apps and automation frameworks designed to elevate your QA skills. Become a Pro Member!

Intro to Appium

appium-featured-image

Welcome to the first part of our Mastering QA series, where we delve into the world of Appium, a powerful open-source tool for mobile app automation. Appium allows you to write tests for iOS and Android applications using the same API, which makes it a versatile and indispensable tool for QA engineers.

appium-desktop-app
Appium Desktop App

What is Appium?

Appium is an open-source tool for automating mobile applications. It allows you to write tests for mobile apps on Android and iOS platforms using a variety of programming languages, such as Java, Python, Ruby, and more. Appium is built on the philosophy that testing native or hybrid apps shouldn’t require including an SDK or recompiling your app.

appium-server-running
Appium Server Running

Key Features of Appium

  • Cross-Platform: Supports testing on both Android and iOS.
  • Multiple Languages: Write tests in any language that has a Selenium client library.
  • Open Source: Free to use and has a large, active community.
  • No App Modification: No need to modify or recompile your app for testing.
Understanding Android Desired Capabilities

When setting up your testing environment for Android applications, it's crucial to configure the desired capabilities properly. For our setup, we define the following properties:

  • PLATFORM_NAME: Android
  • PLATFORM_VERSION: 13.0
  • DEVICE_NAME: emulator-5554
  • APP: [Your app path here]
  • AUTOMATION_NAME: Flutter (for Flutter applications), for typical Android  frameworks use UIAutomator2
android-desired-capabilities
Android Desired Capabilities Setup
Understanding IOS Desired Capabilities

To set up your iOS testing environment, configure the following Desired Capabilities:

  • PLATFORM_NAME: iOS
  • PLATFORM_VERSION: 17.0.1
  • DEVICE_NAME: iPhone 15 Pro
  • UDID: [Add your device ID here]
  • APP: [Your app path here]
  • AUTOMATION_NAME: Use Flutter for Flutter applications, or opt for XCUITest for native iOS testing.

Additionally, ensure to include:

  • xcodeOrgID: [Your Xcode organization ID]
  • xcodeSigningID: [Your Xcode signing ID]

This configuration ensures a seamless testing experience across iOS platforms, leveraging the latest capabilities and features.

ios-desired-capabilities
IOS Desired Capabilities Setup

Why Use Appium

Appium stands out for several reasons, here are a few to consider.

  • Versatility: It supports a wide range of mobile applications, including native, hybrid, and mobile web applications.
  • Flexibility: You can use your preferred development tools, practices, and frameworks.
  • Integration: Easily integrates with popular CI/CD tools, enhancing your development workflow.
  • Community: Strong community support ensures continuous improvement and a wealth of shared knowledge and resources.

Conclusion

Now that you have a basic understanding of what Appium is and why it’s beneficial, it’s time to get hands-on. In the next guide, we’ll walk you through Setting up Appium on Your Local Machine.

 

Setting Up Appium on Local Machine

appium-featured-image

In the previous guide, we introduced you to Appium and its benefits. Now, let’s get started with setting up Appium on your local machine so you can begin writing and executing your tests.

Prerequisites

Before you start, ensure you have the following installed.

  • Java Development Kit (JDK): Appium requires Java, so download and install the JDK.
  • Node.js: Appium is built on Node.js, so you'll need to install it.
  • Android SDK: Necessary for Android app testing.
  • [conditional_data dependency="Windows"]Xcode: N/A[/conditional_data][conditional_data dependency="Mac"]Xcode: Required for iOS app testing.[/conditional_data]

Getting Started

Install Java and Configure the Environment Variables.

  1. Download and install the JDK from the Oracle website.
  2. Next we are going to setup the JAVA_HOME and update the PATH environment variable to ensure Java is configured correctly on your system.

Install Node.js

Installing Node.js is essential for setting up Appium, as Appium relies on Node.js. With Node.js, you can run the Appium server and use npm to install Appium and its dependencies efficiently. This setup is crucial for automating mobile application tests on both Android and iOS platforms.

Install Appium CLI & Appium Doctor Commands

Install Appium: Appium is an open-source tool for automating mobile applications on Android and iOS. To get started, you need to install Appium and its dependencies:

  • Open your [conditional_data dependency="windows"]Command Prompt[/conditional_data][conditional_data dependency="mac"]Terminal[/conditional_data] and run the following command.
bash
npm install -g appium

Install Appium Doctor: Appium Doctor is a tool that helps you verify that all the dependencies required for running Appium are properly installed on your system. It checks for Node.js, Java, Android SDK, Xcode and more.

Install Appium Desktop GUI

Appium Desktop is a graphical user interface (GUI) for Appium, providing an easy way to interact with the Appium server and inspect mobile application elements. It simplifies the process of setting up and managing Appium sessions, making it an essential tool for mobile test automation.
appium-desktop-app
Appium Desktop App

Install Android SDK

To use Appium for automating tests on Android devices, you need to install the Android Software Development Kit (SDK). The Android SDK provides the necessary tools and libraries for developing and testing Android applications. It includes the Android platform tools, such as adb, which Appium uses to interact with Android devices and emulators.

Configure Android Environment Variables

  • Set ANDROID_HOME and update the PATH environment variable.
.bash_profile/.zshrc
export ANDROID_HOME=/path/to/android/sdk
export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH

Install Xcode

To use Appium for testing iOS applications, you’ll need to install Xcode on your Mac. Xcode is Apple’s integrated development environment (IDE) for macOS, used for developing software for iOS, macOS, watchOS, and tvOS. It includes a suite of software development tools, including the iOS Simulator, which is essential for testing iOS apps with Appium.

xcode-in-the-mac-appstore
Searching For XCode In Mac App Store
  • Follow this guide below to Setuo Xcode on your machine.



Conclusion

Congratulations! You have successfully set up Appium on your local machine. Now you’re ready to write your first test case with Appium. In the next guide, we’ll walk you through Writing Your First Appium Test Case with Appium.

Writing Your First Test Case with Appium

appium-featured-image

Now that you have Appium set up on your local machine, it’s time to dive into writing your first test case. This guide will walk you through the process of creating a simple test case in Java.

Create a New Maven Project

Use your favorite IDE to create a new Maven project. We’re going to be using Eclipse in this setup.

appium-launching-eclipse-ide
Eclipse IDE Launching

Creating A New Project

  • Start a new project by navigating to the top menu and selecting File then New and finally Other...
file-new-other
File > New > Other
  • In the wizard window that appears, scroll down to find the Maven folder. Expand the Maven folder by clicking on the small triangle next to it, and then select Maven Project. Click Next to proceed with the project setup.
choosing-maven-project
Choosing Maven Project
  • In the next step of the wizard, you will see an option to create a simple project. To proceed, click the checkbox labeled Create a simple project (skip archetype selection). Once you have checked this option, click the Next > button to move forward with the project setup.
eclipse-check-the-create-a-simple-project-box
Check The Create A Simple Project Box
  • On the next step of the wizard, you will need to create a group ID and an artifact ID for your project. For this guide, use com.test.app.todo as both the group ID and artifact ID. Enter these values in the respective fields provided. After filling in the details, click the Finish button to continue.
eclipse-create-a-group-id-and-artifact-id-name
Create a Group Id & Artifact Id name

Create a New Test Class

With our Maven project created, the next step is to create a new test class. Navigate to the directory src/test/java/. Inside this directory, create a new package by following this path: com.test.

create-new-package-store-test-files
Create A New Package To Store Your Test Files
setting-com-test-as-a-package-name
Setting 'com.test' As A Package Name

Once the package is created, add a new class within it and name the class FirstAppiumTest.

creating-a-new-class
Creating A New Class
setting-the-class-name-as-firstappiumtest
Set The Class Name As FirstAppiumTest
firstappiumtest-class-created
The FirstAppiumTest Class Is Created

Add Dependencies to pom.xml

Now, navigate to the pom.xml file in your project. This file is essential for managing your project’s dependencies and configurations. Open the pom.xml file, as we will be adding the necessary dependencies to run an Appium test script. Once the file is open, so we can add the xml dependencies below.

pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>test-todo-app</groupId>
	<artifactId>test-todo-app</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<maven.compiler.source>17</maven.compiler.source>
		<maven.compiler.target>17</maven.compiler.target>
	</properties>
	<dependencies>
		<dependency>
			<groupId>io.appium</groupId>
			<artifactId>java-client</artifactId>
			<version>8.3.0</version>
		</dependency>
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-java</artifactId>
			<version>4.7.0</version>
		</dependency>
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-remote-driver</artifactId>
			<version>4.7.0</version>
		</dependency>
		<dependency>
			<groupId>org.hamcrest</groupId>
			<artifactId>hamcrest</artifactId>
			<version>2.2</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.11.0</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>3.0.0-M5</version>
			</plugin>
		</plugins>
	</build>
</project>

Add Your APK To The Project

To add your test APK to your project, begin by creating a new directory within your project’s structure. Navigate to the src/test/resources/ directory. Within this directory, create a new folder named app. This is where you will store your APK file for testing purposes.

create-new-apps-folder
Create A New Folder To Store The Test App
setting-the-directory-as-app
Setting The Directory As 'App'
added-the-test-app-in-the-app-folder
Added The Test App In The 'App' Folder

Write Your First Test Script

Let’s take a look at our test application and discuss the test scenario that we’ll be automating. The test application we’ll be using is a TODO app. If you need access to the APK file, please join our Patreon. Members get access to all the existing frameworks we’ve created and more. You can follow along with this guide or use your own test application and tweak the elements as needed. In this test, our goal is to simply click on the Add Task button to display the Add Task screen.

add-a-task-button
Add A Task Button
viewing-add-task-screen
Viewing Add Task Screen
FirstAppiumTest.java
package com.test;

import io.appium.java_client.android.AndroidDriver;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

public class FirstAppiumTest {

    public static void main(String[] args) throws MalformedURLException, InterruptedException {

    	File app = new File("src/test/resources/app/app-debug.apk");

    	 // Set the desired capabilities for your test
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("deviceName", "emulator-5554");
        caps.setCapability("platformName", "android");
        caps.setCapability("app",app.getAbsolutePath());

        // Initialize the Appium driver
        AndroidDriver driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps);

        // Add test case scenario here

        WebElement addTaskButton = driver.findElement(By.id("ADD_YOUR_ID_HERE"));
        addTaskButton.click();
        // quick debug wait for 1 seconds
        Thread.sleep(1000);
        // Close the driver session
        driver.quit();
    }
}

Launch Appium Desktop & Appium Inspector

Now, we need to find the id associated with the element that we want to click. To locate the id element or other useful selectors, ensure that the emulator or device is booted up. First, launch the Appium Server and Inspector. Open the Appium Desktop Server and click the startServer button. Next, launch the Appium Inspector, making sure that the server port matches the Appium server’s port.

appium-desktop-with-emulator
Appium Desktop with Emulator
appium-server-running
Appium Server Is Running
appium-inspector-setup
Appium Inspector + Setting Up Desired Capabilities
  1. Ensure the Remote Port is set to 4273
  2. Set the Remote Path to /wd/hub
  3. Click the pencil & Copy the Desired Capabilities from below and paste in the JSON Representation box
  4. Click the Save button
  5. Click the Start Session button

Desired Capabilities JSON

DesiredCapabilities.json
{
  "appium:platformName": "Android",
  "appium:platformVersion": "13.0", 
  "appium:deviceName": "emulator-5554",
  "appium:automationName": "UiAutomator2",
  "appium:app": "/Users/{userName}/eclipse-workspace/test-todo-app/src/test/resources/app/app-debug.apk",
  "appium:appWaitForLaunch": true
}

Inspecting The App Elements

With the Appium Inspector now launched, you should see a preview of your application. In the preview window, locate and click on the element for which you want to retrieve attributes. For the purposes of this guide, we will click on the Add Task button. By doing so, the attributes related to this specific element will be displayed, allowing you to inspect and utilize them as needed.

appium-inspector-viewing-elements-propertie
Appium Inspector Viewing The Element's Properties
  1. The accessibility id: value is to Add Task
  2. The id: value is to com.example.todoapp:id/fab
  3. The xpath: value is to //android.widget.ImageButton[@content-desc="Add Task"]

You have the flexibility to use any available selector, but for this guide, we will select the second option, which represents the id attribute with the value com.example.todapp:id/fab. This value will be used in our code. Close the Appium Inspector Session to free up the Appium Server 4273 port.

Copy this id value and navigate to the FirstAppiumTest class in your project. Find the element designated for adding a task and paste the copied id value into the addTaskButton element. This ensures that our test script can correctly interact with the element.

finding-add-task-button-element-by-id
Finding Add Task Button Element By ID
Java
WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab"));
addTaskButton.click();
// quick debug wait for 1 seconds
Thread.sleep(1000);
System.out.println("TEST PASSED!");
// Close the driver session
driver.quit();

Run Your Test

Finally, it’s time to run the script. Yay! In the FirstAppiumTest class, right-click to open the context menu. Navigate to Run As and select Java Application. Now, sit back and watch as your script takes off for the first time! If everything goes well, you will see TEST PASSED in the console.

appium-run-as-java-application
Appium Run As Java Application

Analyze the Test Results

After the test execution is complete, review the results to ensure your test case ran successfully. Later in this series, we will learn how to implement TestNG to organize tests based on industry standards. 

appium-test-results-passed
Test Results - Passed
running-test-appium-test-script
Running Appium Test Script

Conclusion

You have now learned how to perform basic UI testing with Appium. This includes finding elements and performing actions. In the next guide, we’ll take a closer look at Organizing Multiple Test Scenarios In Appium with TestNG.

Organizing Multiple Test Scenarios in Appium Using TestNG

appium-featured-image

In the dynamic world of mobile application testing, managing and organizing multiple test scenarios efficiently is crucial for ensuring robust and reliable testing. Appium, combined with TestNG, provides a powerful framework to achieve this. This guide will walk you through the process of organizing multiple test scenarios in Appium using TestNG, leveraging the power of Java. Whether you’re a beginner or an advanced user, this comprehensive guide will help you streamline your test automation process and enhance your testing capabilities. We will be using the project we setup previously. 

Setting Up Maven Project

Let’s navigate to the pom.xml file so we can add the TestNG dependency. We’ll be using TestNG version 7.1.0 for our project.

add-testng-dependency-to-pom-file
Adding TestNG Dependency To pom.xml
TestNG Dependency (pom.xml)
<dependency>
	<groupId>org.testng</groupId>
	<artifactId>testng</artifactId>
	<version>7.1.0</version>
	<scope>compile</scope>
</dependency>

By adding the TestNG dependency to your Maven project, you now have the necessary annotations to write and execute TestNG tests within the Appium project.

Creating TestNG Class

Let’s head back to our directory /src/test/java/com/test/ where we’ll create a copy of the existing FirstAppiumTest class. We’ll then rename this copy to FirstAppiumTestNG to begin restructuring the test to support TestNG. This new class will serve as our foundation for integrating TestNG functionalities.
appium-copying-class
Copying FirstAppiumTest Class
appium-pasting-firstappiumtest-class
Pasting FirstAppiumTest Class
rename-copied-file-to-firstappiumtestng
Rename Copied File to FirstAppiumTestNG

Importing TestNG Annotations

In the newly created FirstAppiumTestNG class, begin by importing the necessary TestNG annotations. These will include @BeforeClass, @AfterClass, and @Test.

FirstAppiumTestNG.class
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
  • The @BeforeClass annotation will be used to set up the Appium driver before any tests are run, ensuring that the environment is correctly initialized.
  • Similarly, the @AfterClass annotation will handle the teardown process, cleaning up resources once all tests have been executed.
  • The @Test annotation will be applied to individual test methods, marking them as TestNG test cases.

Modifying Class To Support TestNG

So what we’re going to do is remove the main() function call and close the curly bracket from our initial setup. Next, we will create a new public static AndroidDriver variable called driver

BeforeClass

In the @BeforeClass method, we will move the Desired Capabilities setup into the setup() function. This approach ensures that our Appium driver is properly configured before any tests are execute.

moving-desired-capabilities-to-beforeclass-method
Moving Desired Capabilities To BeforeClass Method

Test Method

In the @Test method, we will add our simple test case from the previous guide, which is to click the Add Task button. This test will validate that our application responds correctly when adding a new task. By organizing our tests this way, we maintain a clear separation of concerns, making our test cases easier to manage and understand.

appium-testng-test-class
Moving Scenario To Test Method

AfterClass Method

Finally, we’ll move the driver.quit() function into the @AfterClass teardown method. This adjustment ensures that the Appium driver is properly closed after all tests have been executed, cleaning up any resources used during the test run.

moving-the-closing-of-the-driver-in-afterclass-method
Moving The Closing of the Driver in AfterClass Method
FirstAppiumTestNG.class (w/ Before & After Methods)
package com.test;

import io.appium.java_client.android.AndroidDriver;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class FirstAppiumTestNG {

	public static AndroidDriver driver;

	 @BeforeClass
	    public void setUp() throws MalformedURLException {
			File app = new File("src/test/resources/app/app-debug.apk");
		    // Set the desired capabilities for your test
		     DesiredCapabilities caps = new DesiredCapabilities();
		     caps.setCapability("deviceName", "emulator-5554");
		     caps.setCapability("platformName", "android");
		     caps.setCapability("app",app.getAbsolutePath());

		     // Initialize the Appium driver
		     driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps);

	    }

	    @Test
	    public void clickingAddTaskButton() throws InterruptedException {
	       // Add test case scenario here
	        WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab"));
	        addTaskButton.click();
	        // quick debug wait for 1 seconds
	        Thread.sleep(1000);
	        System.out.println("TEST PASSED!");

	    }

	    @AfterClass
	    public void tearDown() {
	        if (driver != null) {
	            // Close the driver session
		        driver.quit();
	        }	    }

    }

Adding More Test & Assertions

Why stop here? Next, we’ll add some assertions and create two more test scenarios to highlight the beauty of TestNG running multiple scenarios and validating our expectations. We will create new tests called addingTaskToDoTheList() and deletingTaskFromTheList(), similar to the test we created using Espresso in our Android guides. We will add these methods to our file, and then we should be ready to run our tests.

In our first new test scenario, we focus on adding a task to our to-do list. This test begins by clicking the “Add Task” button to navigate to the task addition screen. We verify that the user is on the correct screen by checking the presence of the title input field. Here’s how the implementation looks:

Test: clickingAddTaskButton()
@Test
public void clickingAddTaskButton() throws InterruptedException {
    // Add test case scenario here
    WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab"));
    addTaskButton.click();
    // quick debug wait for 2 seconds
    Thread.sleep(2000);
    WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText"));
    Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen");
    driver.navigate().back();
    Thread.sleep(1000);
}

addingTaskToDoTheList() Test

Next, we have the addingTaskToDoTheList() method, which adds a task to the to-do list. This method clicks the “Add Task” button, enters a title and description for the new task, and then saves it. After saving, it verifies that the new task appears in the task list.

Test: addingTaskToDoTheList()
@Test
public void addingTaskToDoTheList() throws InterruptedException {
    WebElement addTaskButton, saveButton;
    WebElement addTaskTitleField, addTaskDescField;

    // click the Add Task button
    addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab"));
    addTaskButton.click();
    // quick debug wait for 2 seconds
    Thread.sleep(2000);
    // add title to the task
    addTaskTitleField = driver.findElement(By.id("com.example.todoapp:id/titleEditText"));
    addTaskTitleField.click();
    addTaskTitleField.sendKeys("Buy Milk");

    // add description to the task
    addTaskDescField = driver.findElement(By.id("com.example.todoapp:id/descriptionEditText"));
    addTaskDescField.click();
    addTaskDescField.sendKeys("Grab 2 Gallons of Milk");

    // click the Save button
    saveButton = driver.findElement(By.id("com.example.todoapp:id/saveButton"));
    saveButton.click();
    // quick debug wait for 2 seconds
    Thread.sleep(2000);
    WebElement newTaskAdded = driver.findElement(By.id("com.example.todoapp:id/textView"));
    Assert.assertEquals(newTaskAdded.getText().toString(), "Buy Milk", "New Task Found");
}

deletingTaskFromTheList() Test

Finally, we have the deletingTaskFromTheList() method, which tests the deletion of a task from the list. This method locates the delete button and clicks it, then verifies that the task is removed from the task list.

Test: deletingTaskFromTheList()
@Test
public void deletingTaskFromTheList() throws InterruptedException {
    WebElement deleteButton;
    // click the Delete button
    deleteButton = driver.findElement(By.id("com.example.todoapp:id/doneButton"));
    deleteButton.click();
    // quick debug wait for 2 seconds
    Thread.sleep(2000);
    Assert.assertTrue(true, "Task is deleted & is removed from the Task List Screen");
}

Full Implementation

Here’s the full implementation of the FirstAppiumTestNG file.

FirstAppiumTestNG.class
package com.test;

import io.appium.java_client.android.AndroidDriver;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class FirstAppiumTestNG {

	public static AndroidDriver driver;

	 @BeforeClass
	    public void setUp() throws MalformedURLException {
			File app = new File("src/test/resources/app/app-debug.apk");
		    // Set the desired capabilities for your test
		     DesiredCapabilities caps = new DesiredCapabilities();
		     caps.setCapability("deviceName", "emulator-5554");
		     caps.setCapability("platformName", "android");
		     caps.setCapability("app",app.getAbsolutePath());

		     // Initialize the Appium driver
		     driver = new AndroidDriver (new URL("http://127.0.0.1:4273/wd/hub"), caps);

	    }

	    @Test
	    public void clickingAddTaskButton() throws InterruptedException {
	       // Add test case scenario here
	        WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab"));
	        addTaskButton.click();
	        // quick debug wait for 2 seconds
	        Thread.sleep(2000);
	        WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText"));
	        Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen");
	        driver.navigate().back();
	        Thread.sleep(1000);
	    }

	    @Test
	    public void addingTaskToDoTheList() throws InterruptedException {
	       WebElement addTaskButton,saveButton;
	       WebElement addTaskTitleField,addTaskDescField;

	        // click the Add Task button
	        addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab"));
	        addTaskButton.click();
	        // quick debug wait for 2 seconds
	        Thread.sleep(2000);
	        // add title to the task
	        addTaskTitleField = driver.findElement(By.id("com.example.todoapp:id/titleEditText"));
	        addTaskTitleField.click();
	        addTaskTitleField.sendKeys("Buy Milk");

	        // add description to the task
	        addTaskDescField = driver.findElement(By.id("com.example.todoapp:id/descriptionEditText"));
	        addTaskDescField.click();
	        addTaskDescField.sendKeys("Grab 2 Gallons of Milk");

	        // click the Save button
	        saveButton = driver.findElement(By.id("com.example.todoapp:id/saveButton"));
	        saveButton.click();
	       // quick debug wait for 2 seconds
	        Thread.sleep(2000);
	        WebElement newTaskAdded = driver.findElement(By.id("com.example.todoapp:id/textView"));
	        Assert.assertEquals(newTaskAdded.getText().toString(), "Buy Milk", "New Task Found");
	    }

	    @Test
	    public void deletingTaskFromTheList() throws InterruptedException {
		   WebElement deleteButton;
		    // click the Delete button
		    deleteButton = driver.findElement(By.id("com.example.todoapp:id/doneButton"));
		    deleteButton.click();
		    // quick debug wait for 2 seconds
	        Thread.sleep(2000);
		    Assert.assertTrue(true, "Task is deleted & is removed from the Task List Screen");

		    }

	    @AfterClass
	    public void tearDown() {
	        if (driver != null) {
	            // Close the driver session
		        driver.quit();
	        }	    }

    }

Running Test: TestNG XML File Setup

Now that we’re ready to run our test, let’s create a new testng.xml file in the root of our project. In this new file, we’ll add the XML code below to enable running our FirstAppiumTestNG class.

TestNG Suite Config (testng.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="My First Appium TestNG Test">
    <test name="TODO App Automation Testing">
         <classes>
            <class name="com.test.FirstAppiumTestNG"/>
          </classes>
     </test> <!-- Test -->
</suite> <!-- Suite -->
appium-testng-create-new-file
Create A New TestNG File
appium-testng-file-name
Naming The File testng.xml
pasting-xml-script-testng
Pasting The XML Script In The New Testng.xml File

To properly run our TestNG XML file, we need to configure the pom.xml file accordingly. Start by opening your pom.xml file and locating the Maven Surefire Plugin section. Within this section, you’ll need to add the TestNG configuration. Specifically, scroll down to where you see the <version> tag within the Maven Surefire Plugin and insert the following configuration just below it:

TestNG Suite Setup (pom.xml)
<configuration>
  <suiteXmlFiles>
    <suiteXmlFile>testng.xml</suiteXmlFile>
  </suiteXmlFiles>
  <testFailureIgnore>false</testFailureIgnore>
</configuration>
appium-update-testng-xml-file
Pasting TestNG XML Configuration

This snippet tells Maven to use the testng.xml file to determine which tests to run. The <testFailureIgnore> tag is set to false, ensuring that the build will fail if any test fails, which is often the desired behavior in a continuous integration environment.

Once you’ve added this configuration, make sure to save your pom.xml file. With these changes in place, your project is now ready to run with the specified TestNG configuration.

  1. Let's open the Terminal in Eclipse so we can execute the Maven command.
  2. Type or copy the command mvn test -DsuiteXmlFile=testng.xml into the Terminal.
  3. Press Enter to execute.
  4. The script should begin running the three scenarios we created earlier.
  5. As the tests execute, you should see passing logs appear in the console, indicating successful execution.
appium-mvn-command
Pasting Maven Command To Run TestNG
appium-console-results
Successful Test Results After Running Command

Running Test: TestNG Plugin

Alternatively, if you have the TestNG plugin installed on your IDE, you can simply right-click on the test file and choose Run As TestNG. This method provides a quick and easy way to execute your tests without the need to manually configure the XML file. class.

appium-testng-run-via-plugin
Running Test File Using 'Run As TestNG'

Running FirstAppiumTestNG Script

Alright, let’s sit back and enjoy watching the results. In the video below, you’ll see the script in action as it runs via the mvn command. The test executes all three scenarios and they pass successfully! It’s always a great feeling when everything works perfectly, isn’t it? Yay!

appium-running-tesng-test
GIF: Script Is Running
appium-testnt-results-pane
TestNG Results Pane
appium-tesng-html-results
TestNG HTML Web Results

Conclusion

Organizing multiple test scenarios in Appium using TestNG is a critical step in building a robust test automation strategy. With TestNG, we can group our test cases logically, execute them in a specific order, and generate detailed reports. This structured approach not only saves time but also minimizes errors, making our testing process more reliable and efficient. Stay tuned for our next topic, where we will delve into Understanding Appium UI Locators.

Understanding Appium UI Locator Strategies

appium-featured-image

In this guide, we will delve into Appium UI Locator Strategies. Understanding how to efficiently locate elements is crucial for creating robust and maintainable automated tests. This guide is designed to be comprehensive and accessible for both beginners and advanced users. By the end of this guide, you’ll be proficient in various locator strategies in Appium, using Java as our code language.

Introduction to Locators

Locators are used to find UI elements on the mobile application. Appium supports various locator strategies:

  • ID - is a unique identifier for elements. It is one of the most reliable and fastest ways to locate elements.
  • Name - is another attribute that can be used, although it's less common and sometimes deprecated.
  • Class Name - locates elements by their class attribute. It can return multiple elements, so it's often used with other strategies.
  • XPath - is a powerful and flexible locator strategy but can be slower and more brittle. It's often used when other locators are not available.
  • iOS Predicate String (iOS) - iOS Predicate String is used for complex queries on iOS.
  • iOS Class Chain (iOS) - iOS Class Chain is another iOS-specific strategy that allows chaining class names and attributes.

Using ID

Using an id is one of the most efficient ways to identify and capture elements in Appium, provided that this option is available in our inspector. The id attribute serves as a unique identifier for elements within the DOM, allowing for precise and reliable element selection. This method is particularly advantageous because IDs are designed to be unique within a given page, thereby reducing the risk of selecting the wrong element.
By.id
WebElement taskButton = driver.findElement(By.id("add-task-button"));

Using Name

By using the name attribute, you ensure your code remains clear and intuitive. This method not only enhances readability but also reduces the risk of errors that can occur with more complex locators. It’s a straightforward way to improve your Appium testing strategy, making it easier to manage and scale your automated tests. Adopting this practice can lead to more robust and reliable test scripts, ultimately contributing to a more efficient development cycle.
By.name
WebElement taskButton = driver.findElement(By.name("add-task-button"));

Using XPath

When using xpath to identify an element in Appium, you can target specific attributes or hierarchical relationships within the UI structure. For example, you might want to locate a button based on its ID, class, or even its position relative to other elements. This flexibility is one of the key advantages of using xpath over other locating strategies.
By.xpath
WebElement taskButton = driver.findElement(By.xpath("//android.widget.Button[@content-desc='SIGN IN']"));

Using Class Name

You can capture and interact with an element by specifying its className. This method is particularly useful when elements share common characteristics or belong to the same class.
By.className
WebElement taskButton = driver.findElement(By.className("android.widget.Button"));

[IOS] iOS Predicate String

This technique offers a precise way to locate elements based on specific attributes. The iOS Predicate String is a powerful tool that leverages the NSPredicate class from Apple’s iOS development environment, allowing developers to create complex queries for UI elements.

[IOS] iOS Class Chain

This approach leverages the class chain strategy, providing a powerful alternative to traditional locator strategies. By utilizing iOSClassChain, developers can efficiently target elements based on their hierarchical structure, enhancing the precision of their UI automation tests.
By.iOSClassChain
WebElement taskButton = driver.findElement(By.iOSClassChain("**/XCUIElementTypeButton[`label == 'Task'`]"));

Conclusion

In this guide, we explored various Appium UI locator strategies using Java. By mastering these locators, you can write efficient and reliable automated tests for your mobile applications. Remember to prioritize IDs and Accessibility IDs for their reliability and speed, and use XPath judiciously. Stay tuned for our next topic, where we will dive into Advanced Automating Gestures in Appium.

 

Automating Gesture Actions in Appium

appium-featured-image

In the previous guide, we learned about Appium UI Locator Strategies. Now, let’s take it a step further by automating gesture actions. Gestures such as swipes, scrolls, and taps are essential for comprehensive mobile app testing.

Common Gesture Actions

Alright, let’s dive into Gesture Actions in Appium. These actions are essential for simulating complex interactions with your mobile app, mimicking how a real user would engage with it. Whether you need to swipe, pinch, zoom, or perform a drag-and-drop action, Appium’s gesture commands have you covered. These gestures are critical for testing user interfaces that rely heavily on touch interactions, ensuring your app behaves as expected in the hands of actual users.

Create Gestures Util Class

Let’s dive right in and enhance our Appium project by adding a new class to handle gesture methods efficiently. To begin, we’ll create a new class called GesturesUtil which will serve as a repository for various gesture methods. This step is essential to keep our code organized and maintainable.

  • First, navigate to your project directory and create a new package namedcom.helpers.
  • This package will be the home for our GesturesUtilclass.
  • Organizing your code into packages not only improves readability but also aligns with best practices in software development, making your project more modular and easier to manage.

Import Dependencies

In the com.helpers package, create the GesturesUtil class. This class will encapsulate all the gesture methods you need for your Appium tests, such as swipe, tap, and scroll. 

To get started, the first step is importing the necessary dependencies. In your project, add the following imports:

GesturesUtil.class
import io.appium.java_client.AppiumDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.PointerInput;
import org.openqa.selenium.interactions.Sequence;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;

With these imports in place, you can now proceed to define your gesture methods without encountering any compilation issues. This setup ensures that your code is well-structured and ready to handle a variety of automated testing scenarios, making your Appium testing framework robust and efficient.

Simulating Tap or Long Press

A tap is simply a quick touch on the screen, often used for selecting items, while a long press involves holding down on an element for a longer duration. This is typically used for actions like bringing up a context menu or initiating a special function. Appium’s capabilities allow you to simulate both, ensuring that these interactions are tested thoroughly.
Gesture: tapElement
public void tapElement(WebElement element) {
    PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
    Sequence tap = new Sequence(finger, 1)
            .addAction(finger.createPointerMove(Duration.ZERO,
                    PointerInput.Origin.viewport(), element.getLocation().x + element.getSize().width / 2, element.getLocation().y + element.getSize().height / 2))
            .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
            .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
    driver.perform(Collections.singletonList(tap));
}

Tap

The tapElement method simulates a tap on a web element by:

  • Creating a touch input named finger.
  • Creating a sequence of actions that:
    - Moves the touch pointer to the center of the specified element.
    - Presses down on the element.
    - Releases the press.
  • Perform the sequence of actions using the driver.
Gesture: Long Press
public void longPressElement(WebElement element, Duration duration) {
    PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
    Sequence longPress = new Sequence(finger, 1)
            .addAction(finger.createPointerMove(Duration.ZERO,
                    PointerInput.Origin.viewport(), element.getLocation().x + element.getSize().width / 2, element.getLocation().y + element.getSize().height / 2))
            .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
            .addAction(finger.createPointerMove(duration, PointerInput.Origin.viewport(), element.getLocation().x,element.getLocation().y))
            .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
    driver.perform(Collections.singletonList(longPress));
}

Long Press

The longPressElement method simulates a long press on a mobile or web element by:

  1. Moving the virtual finger to the center of the element.
  2. Pressing down on the element.
  3. Holding the press for a specified duration.
  4. Releasing the press.

Simulating Swipe Gestures

In Appium, swiping is straightforward but powerful, allowing you to simulate the user’s finger moving across the screen.

To implement a swipe, you define the start and end coordinates, which tells Appium where the swipe should begin and end. By fine-tuning these coordinates, you can create swipes that mimic natural user behavior, ensuring your test cases are as realistic as possible.

Gesture: Swipe
public void swipe(int startX, int startY, int endX, int endY, Duration duration) {
    PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
    Sequence swipe = new Sequence(finger, 1)
            .addAction(finger.createPointerMove(Duration.ZERO,
                    PointerInput.Origin.viewport(), startX, startY))
            .addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
            .addAction(finger.createPointerMove(duration,
                    PointerInput.Origin.viewport(), endX, endY))
            .addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
    driver.perform(Collections.singletonList(swipe));
}

Swipe

The swipe function simulates a swipe gesture on a touch screen.

  1. First, it moves the touch pointer from a starting point (startX, startY)
  2. Next it moves to the ending point (endX, endY) over a given duration.
  3. The process involves moving the pointer to the start position, touching down, moving to the end position, and then lifting up
  4. All of these actions are coordinated through a sequence of actions performed by the driver.

Simulating a Zoom In

Next we have pinch and zoom gestures, which are indispensable for applications that involve maps, images, or any form of visual content that users might need to zoom in and out of.

Gesture: Zoom In
public void zoomIn(WebElement element) {
    int centerX = element.getLocation().getX() + element.getSize().getWidth() / 2;
    int centerY = element.getLocation().getY() + element.getSize().getHeight() / 2;
    int endX1 = centerX - 100;
    int endY1 = centerY - 100;
    int endX2 = centerX + 100;
    int endY2 = centerY + 100;

    PointerInput finger1 = new PointerInput(PointerInput.Kind.TOUCH, "finger1");
    Sequence pinch1 = new Sequence(finger1, 1)
            .addAction(finger1.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerX, centerY))
            .addAction(finger1.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
            .addAction(finger1.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), endX1, endY1))
            .addAction(finger1.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));

    PointerInput finger2 = new PointerInput(PointerInput.Kind.TOUCH, "finger2");
    Sequence pinch2 = new Sequence(finger2, 1)
            .addAction(finger2.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), centerX, centerY))
            .addAction(finger2.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
            .addAction(finger2.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), endX2, endY2))
            .addAction(finger2.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));

    driver.perform(Arrays.asList(pinch1, pinch2));
}

Pinching

Pinching involves bringing two fingers together on the screen, while zooming involves spreading them apart. Appium handles these multi-touch gestures by specifying the touch points and their movements, giving you precise control over the interactions.

  1. Calculate the center coordinates (centerX, centerY)of the element.
  2. Define end coordinates for the pinch gesture (endX1, endY1, endX2, endY2).
  3. Create the first finger input sequence pinch1to:
    - Move to the center of the element.
    - Press down.
    - Move to the end coordinates over 600 ms.
    - Lift up the finger.
  4. Create the seond finger input sequence pinch2 to:
    - Move to the center of the element.
    - Press down.
    - Move to the end coordinates over 600 ms.
    - Lift up the finger.
  5. Execute both sequences simultaneously to perform the pinch gesture.

Simulating a Zoom Out

Perform a zoom out gesture by reversing the pinch gesture:

Gesture: Zoom Out
public void zoomOut(WebElement element) {
    int centerX = element.getLocation().getX() + element.getSize().getWidth() / 2;
    int centerY = element.getLocation().getY() + element.getSize().getHeight() / 2;
    int startX1 = centerX - 100;
    int startY1 = centerY - 100;
    int startX2 = centerX + 100;
    int startY2 = centerY + 100;

    PointerInput finger1 = new PointerInput(PointerInput.Kind.TOUCH, "finger1");
    Sequence pinchIn1 = new Sequence(finger1, 1)
            .addAction(finger1.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startX1, startY1))
            .addAction(finger1.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
            .addAction(finger1.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), centerX, centerY))
            .addAction(finger1.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));

    PointerInput finger2 = new PointerInput(PointerInput.Kind.TOUCH, "finger2");
    Sequence pinchIn2 = new Sequence(finger2, 1)
            .addAction(finger2.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startX2, startY2))
            .addAction(finger2.createPointerDown(PointerInput.MouseButton.LEFT.asArg()))
            .addAction(finger2.createPointerMove(Duration.ofMillis(600), PointerInput.Origin.viewport(), centerX, centerY))
            .addAction(finger2.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));

    driver.perform(Arrays.asList(pinchIn1, pinchIn2));
}

Zooming

Pinching involves bringing two fingers together on the screen, while zooming involves spreading them apart. Appium handles these multi-touch gestures by specifying the touch points and their movements, giving you precise control over the interactions.

  1. Calculate the center coordinates of the element.
  2. Define starting points for two touch actions, positioned diagonally around the center.
  3. Create a touch action sequence for the first finger, moving from the starting point to the center.
  4. Create a touch action sequence for the second finger, moving from the starting point to the center.
  5. Execute both sequences simultaneously to perform the pinch-in gesture.

Conclusion

Incorporating gesture actions into your Appium tests enhances functionality and verifies a seamless user experience. By simulating real user gestures, you can uncover issues that traditional testing may miss, leading to a more robust and user-friendly app.

Whether you’re testing a simple or complex app, mastering these gestures will improve your testing outcomes. In the next guide, you’ll learn about Capturing Screenshots and Logs in Appium.

Capturing Screenshots and Logs In Appium

appium-featured-image

Capturing screenshots and logs during your tests is crucial for diagnosing issues, verifying UI elements, and ensuring your app behaves as expected. Screenshots provide visual evidence, while logs offer detailed information about the app’s behavior, network requests, errors, and more.

Create New Utils Class

Let’s begin by creating a new Utils class, which will be instrumental in managing your screenshot captures and logging methods. To start, navigate to your project and create a new class within the com.helpers package, or alternatively, any directory that suits your organizational preferences.

creating-a-new-utils-class
Creating A New Utils Class
Utils.class
package com.helpers;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.logging.LogEntry;
import org.openqa.selenium.io.FileHandler;
import org.openqa.selenium.logging.LogEntries;
import org.openqa.selenium.logging.LogType;

Capturing Screenshots

To capture screenshots in Appium using Java, you can use the getScreenshotAs method. 

Utils.class
public class Utils {
public static void captureScreenshot(WebDriver driver, String fileName) {
    File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
    try {
        FileHandler.copy(srcFile, new File("./target/screenshots/" + fileName + ".png"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
It’s important to organize your project structure effectively. To achieve this, we’ll create a dedicated /screenshots directory within the target folder of your project. This organization ensures that all screenshots are stored in a centralized location, making them easy to locate and manage.
creating-a-new-screenshots-directory
Creating A New Screenshots Directory
  • For instance, when you capture a screenshot during the automation process, you can save it in this newly created directory.
  • To maintain clarity and avoid confusion, it's essential to give each screenshot file a descriptive name.
  • In this particular example, we will name the screenshot file add_new_task_screen.In this particular example, we will name the screenshot file add_new_task_screen.
  • This naming convention not only helps in identifying the context of the screenshot quickly but also enhances the overall readability and maintainability of your test reports.

Call this method in your test script where you want to capture the screenshot:

 
Test: clickingAddTaskButton()
@Test
public void clickingAddTaskButton() throws InterruptedException {
    // Add test case scenario here
    WebElement addTaskButton = driver.findElement(By.id("com.example.todoapp:id/fab"));
    addTaskButton.click();
    // quick debug wait for 2 seconds
    Thread.sleep(2000);
    WebElement addTaskTitle = driver.findElement(By.id("com.example.todoapp:id/titleEditText"));
    Assert.assertTrue(addTaskTitle.isDisplayed(), "User is on the Add Task Details Screen");
    Utils.captureScreenshot(driver, "add_new_task_screen");
    driver.navigate().back();
    Thread.sleep(1000);


}

When executing your script in Appium, the captured screenshot is stored in the /target/screenshot/ directory. To view the newly captured screenshot, you will need to refresh your project. Once refreshed, the file named add_new_task_screen will appear in the screenshots directory. This step is crucial for verifying that your automation scripts are correctly capturing the visual output you expect.

gif-reviewing-screenshot-image-after-executing-test
GIF: Reviewing Screenshot Image After Executing Test

Capturing Logs

To capture logs in Appium using Java, you can use the getLog method. Here’s how:

Test: captureLogs()
public static void captureLogs(WebDriver driver) {
        LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER);
        for (LogEntry entry : logEntries) {
            System.out.println(entry.getMessage());
        }
}

Call this method in your test script to capture and print the logs:

 
Java
Utils.captureLogs(driver);

Troubleshooting

  • Permission Issues: Ensure your script has write permissions to the directory where screenshots and logs are saved.
  • Driver Compatibility: Make sure the Appium driver versions are compatible with your testing framework and mobile OS.
  • Error Handling: Implement error handling in your scripts to manage exceptions during screenshot or log capture.

Best Practices

  • Organize Screenshots: Save screenshots with meaningful names and organize them in folders based on test cases or test runs.
  • Log Levels: Use different log levels (e.g. INFO, DEBUG, ERROR) to filter logs effectively.
  • Automate Log Analysis: Consider automating log analysis to highlight errors or warnings.
  • Periodic Captures: Capture screenshots and logs periodically during long test runs to monitor app behavior over time.

Conclusion

By now, you should know how to capture screenshots and logs during your Appium test executions. This knowledge will significantly enhance your ability to debug and report on your tests. Continue honing your skills and exploring more advanced topics in Appium and QA testing. Happy testing!

Cucumber (Gherkin)

cucumber-featured-image

Official Docs 

Discover more about Cucumber, the powerful tool for Behavior-Driven Development (BDD). To learn more, visit the official Cucumber Website, where you can explore its features, documentation, and resources.

Become a Pro Member - Unlock Advanced Tools & Resources

Gain exclusive access to test apps and automation frameworks designed to elevate your QA skills. Become a Pro Member!

Introduction to Cucumber and Gherkin

cucumber-guides-featured-image

Welcome to Mastering QA! In this guide, we’ll introduce you to Cucumber and Gherkin, two powerful tools that revolutionize Behavior-Driven Development (BDD). Understanding these tools will provide a strong foundation for writing and automating your tests effectively.

What is Cucumber?

Cucumber is an open-source BDD framework that simplifies the process of defining and executing tests. It encourages collaboration between technical and non-technical team members, fostering better communication and understanding of software requirements.

What is Gherkin?

Gherkin is a human-readable language used to write Cucumber scenarios. It’s designed to be simple, easy to understand, and accessible to non-developers. Gherkin acts as the bridge between plain text descriptions of software behaviors and the automation code that validates those behaviors.

Feature Files

Feature files are where Gherkin shines. These text files have a .feature extension and contain high-level descriptions of software features or functionalities. They serve as documentation and test scripts simultaneously.

Scenarios

Scenarios are individual test cases written in Gherkin. They describe a specific behavior or test case, typically following a Given-When-Then structure. For example:

Scenario: home-screen.feature
Feature: Home Screen - Verify Web App Navigation Menu Links

Scenario: Click the Login Icon
  Given the user is on the home screen
  When the user clicks the "login" icon
  Then the "Login" screen is displayed

This keyword sets the stage for the scenario by describing the initial context or preconditions. It establishes the state of the system before the action occurs.

This keyword defines the action or event that triggers the scenario. It represents the user's interaction with the system or the event that takes place.

This keyword outlines the expected outcome or result after the action is performed. It specifies what should happen as a result of the interaction, allowing for validation of the scenario.

Step Definitions

Step definitions are the automation code that executes the steps in Gherkin scenarios.

Step Defintions
public class HomeStepDefs {
    public WebDriver driver = Hooks.driver;

    @Given("the user is on the home screen")
    public void the_user_is_on_the_home_screen() throws InterruptedException {
       // logic goes here
    }

    @When("the user clicks the {string} icon")
    public void the_user_clicks_the_icon(String iconName) {
        // logic goes here
    }

    @Then("the {string} screen is displayed")
    public void the_screen_is_displayed(String screenName) {
        // logic goes here
    }

    @When("the user clicks the {string} link")
    public void the_user_clicks_the_link(String linkName) {
       // logic goes here

    }
}

Benefits of Cucumber and Gherkin

  • Improved Collaboration: Cucumber and Gherkin facilitate effective communication between technical and non-technical team members, leading to better software understanding.
  • Reusable Steps: Gherkin steps can be reused across multiple scenarios, reducing redundancy and maintenance efforts.
  • Living Documentation: Feature files serve as living documentation that stays up-to-date with your application's behavior.
  • Automation: Cucumber allows you to automate tests based on Gherkin scenarios, making it easier to validate software functionality.

Conclusion

Now that you have a basic understanding of Cucumber and Gherkin, it’s time to Set Up Cucumber in Your Project.

Setting Up Cucumber in Your Project

cucumber-guides-featured-image

In this  guide, we’ll walk you through the essential steps to set up Cucumber in a Java project. Proper setup is crucial for ensuring a smooth workflow for your Behavior-Driven Development (BDD) testing. By following this guide, you’ll be well on your way!

Prerequisites

  • Java Development Kit (JDK) installed.
  • Integrated Development Environment (IDE) Eclipse.
  • Maven for dependency management.

Create a New Maven Project

To embark on your journey with a Cucumber Gherkin project, the first step is to create a new Maven project. If you’re unfamiliar with setting up a Maven project, don’t worry. Our guide here on How To Create A New Maven Project in Eclipse, will walk you through the process step by step.

Once your Maven project is successfully set up, the next crucial task is to add the core Maven dependencies required for your Cucumber Gherkin project. Head over to your pom.xml file and these between your dependencies tag.

adding-dependencies-to-pom-xml
Adding Dependencies To pom.xml
pom.xml
<!-- Selenium Java -->
<dependency>
	<groupId>org.seleniumhq.selenium</groupId>
	<artifactId>selenium-java</artifactId>
	<version>4.20.0</version>
</dependency>

<!-- Cucumber Java -->
<dependency>
	<groupId>io.cucumber</groupId>
	<artifactId>cucumber-java</artifactId>
	<version>7.11.0</version>
</dependency>

<!-- Cucumber JUnit -->
<dependency>
	<groupId>io.cucumber</groupId>
	<artifactId>cucumber-junit</artifactId>
	<version>7.11.0</version>
</dependency>

<!-- JUnit 4 -->
<dependency>
	<groupId>junit</groupId>
	<artifactId>junit</artifactId>
	<version>4.12</version>
	<scope>test</scope>
</dependency>

<!-- Extent Reports Cucumber Adapter -->
<dependency>
	<groupId>tech.grasshopper</groupId>
	<artifactId>extentreports-cucumber7-adapter</artifactId>
	<version>1.14.0</version>
</dependency>

<!-- Extent Reports -->
<dependency>
	<groupId>com.aventstack</groupId>
	<artifactId>extentreports</artifactId>
	<version>5.1.1</version>
</dependency>

<!-- Commons IO -->
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.11.0</version>
</dependency>

Organizing Your Project Structure

Now that we have our project created, let’s set up our base folders and directories. To get started, we’ll need to create a few specific folders. In this guide we’ll be incorporating the com.kicksapp package in our project to keep our files organize.
organizing-cucumber-project
Organizing Cucumber Project
  • com/kicksapp/runners - This folder is where our test runner files will be stored. These files are essential for executing our test suites.
  • com/kicksapp/stepdefs - Here, we'll keep our test step definitions. This organization helps in managing the steps involved in our tests, making them easy to locate and modify.
  • src/test/resources/driver - This is the designated folder for our driver files. For this project, we'll be using Chromedriver. Ensuring the driver is in the right place helps in seamless test execution.
  • src/test/resources/features - Most importantly, this folder will store our feature files. Feature files are the cornerstone of our behavior-driven development (BDD) approach, outlining the scenarios and behaviors our application should exhibit.
Tip: Naming Your Package Directory

You can choose to keep you package as simple as src/test/java/runners or src/test/java/stepdefs. However in this guide We’ll be using the com/kicksapp/… package.

Downloading the Cucumber Plugin for Eclipse

Once we have these packages and folders set up, the next step is to download the Cucumber plugin for Eclipse. This plugin is essential for integrating Cucumber with Eclipse, providing a robust environment for running and managing our BDD tests.

Navigate to the top menu and click on Help . From the dropdown menu, select Eclipse Marketplace…

installing-cucumber-plugin-eclipse-marketplace
Installing Cucumber Plugin From The Eclipse Marketplace
  1. Search for Cucumber: In the Eclipse Marketplace window, use the search bar to type in [direction]"Cucumber"[/direction]. Press Enter to view the search results.
  2. Install the Cucumber Plugin: Locate the Cucumber plugin from the list of results. Click the [direction]Install[/direction] button next to the Cucumber plugin entry. Follow the prompts to complete the installation process.
  3. Restart Eclipse: Once the installation is finished, you will be prompted to restart Eclipse. Click [direction]Restart Now[/direction] to apply the changes.

Conclusion

Organizing your project with these folders ensures a streamlined process where each component of your testing framework is easily accessible. This setup not only enhances productivity but also aligns with best practices in test automation, making it easier to scale and maintain your tests.

Now you’re ready to Write Your First Gherkin Feature File. Continue to the next guide to dive into writing Gherkin scenarios.

 
 
 

Writing Your First Gherkin Feature File

cucumber-guides-featured-image

Now that you have Cucumber set up in your project, it’s time to write your first Gherkin feature file. This guide will help you create a feature file and define scenarios using Gherkin syntax.

Gherkin feature files are written with the .feature extension and contain a structured language with keywords like Feature, Scenario, Given, When, Then, And, and But. Let’s write a simple feature file for a checking the navigation on the Kicks Web App functionality.

kicks-app-flutter-web
Kicks App | Flutter Web

Creating a Feature File

First, navigate to your project’sfeaturesdirectory. This is where all your feature files will reside. To get started with our scenarios, we need to create a new file. Create a file named home-screen.feature inside the features directory.

cucumber-creating-home-screen-feature-file
Creating The Home Screen Feature File
Path: home-screen.feature
src/test/resources/features/home-screen.feature

By creating the home-screen.feature file, we establish a dedicated space for our home screen scenarios. This approach not only helps in organizing our tests but also makes it easier to locate and update them as needed.

Write a Feature Scenario 

Ensuring a seamless user experience starts with verifying that all navigation links on the home screen function as expected. Below we are going test a few test cases related to the navigation menu.

home-screen.feature
# Author: J Richard | Mastering QA
Feature: Home Screen - Verify Web App Navigation Menu Links

  Scenario: Click the Login Icon
    Given the user is on the home screen
    When the user clicks the "login" icon
    Then the "Login" screen is displayed

  Scenario: Click the Products link
    Given the user is on the home screen
    When the user clicks the "Products" link
    Then the "Products" screen is displayed
home-screen-feature-scenarios
Home Screen Feature File Scenarios

Understanding Gherkin Syntax

  • Feature: Provides a detailed overview of the feature being tested, outlining its purpose and functionality.
  • Scenario: Specifies a particular test case for the feature, illustrating a unique situation to validate its performance.
  • Given: Establishes the initial conditions and context necessary for the test to proceed, ensuring a proper setup.
  • When: Captures the specific actions taken by the user during the test, detailing the interactions that trigger the functionality.
  • Then: Articulates the expected results of the test, defining the criteria for success and the desired behavior of the feature.
  • This step sets the initial context. It assumes the user has already landed on the home screen of the web application.
  • This action step simulates the user clicking on the login icon, which is expected to take them to the login screen.
  • The final step verifies the outcome, ensuring that clicking the login icon indeed navigates the user to the login screen.
Click the Products Link Test

The second scenario is pretty much similar but in this case we will be clicking the products link and verifying that we landed there successfully.

Conclusion

You’ve written your first Gherkin feature file. Next, you’ll learn how about Scenario Outlines and Examples. Continue to the next guide to explore step definitions.

Scenario Outlines and Examples

cucumber-guides-featured-image

In this guide, you’ll learn how to use scenario outlines and examples to write more dynamic and data-driven tests. This allows you to test multiple cases with different inputs and expected outcomes efficiently.

What is a Scenario Outline?

A Scenario Outline is a template for a scenario that can be run multiple times with different sets of data. It is useful when you want to test the same scenario with different inputs and expected outcomes. This helps in reducing redundancy and improving the readability and maintainability of your test suite.

Syntax of Scenario Outline

The syntax of a Scenario Outline in Gherkin is as follows:

Gherkin
Scenario Outline: Title of the scenario
  Given some precondition
  When some action is performed
  Then some expected outcome should happen

Examples:
  | parameter1 | parameter2 |
  | value1     | value2     |
  | value3     | value4     |
  • Scenario Outline: This keyword establishes a scenario template that allows for the reuse of the same test steps with varying data inputs, streamlining the testing process.
  • Examples: This section specifies the various sets of data that will be used to fill in the placeholders defined in the Scenario Outline, enabling comprehensive testing of multiple scenarios efficiently.

Using Examples in Scenario Outline

The Examples section contains a table where each row represents a different set of values to be used in the scenario. The values from the table are substituted into the scenario outline, and the scenario is run once for each row.
cucumber-scenario-outline-example
Cucumber Scenario Outline Example

Consider a scenario where we want to test the products filter functionality of the Kicks website with different filters and verifying the item counts. This involves simulating user actions on the website to ensure that the filters for products work as expected.

Gherkin
Feature: Products Page Filters & Stock Count

Scenario Outline: User clicks product filter, choose a gender option and verify item count
  Given the user is on the products screen
  When the user clicks "<filter>" filter option
  And the user clicks the "<gender>" gender option
  And the user clicks a "<size>" shoe
  Then the first sneaker option is "<first_sneaker>"
  And the result is now "<item_count>"

  Examples:
    | filter        | gender | size | first_sneaker          | item_count  |
    | Most popular  | Male   | 10.5 | Adidas Converse        |  7 items    |
    | Lowest price  | Female |    6 | New Balance Streetwear | 13 items    |
    | Highest price | Male   |  9.5 | Jordan Orginal         |  9 items    |
    | Newest        | Female |    7 | Nike Air Max 360       | 14 items    |

This feature focuses on verifying that the product filters on the Kicks website are working correctly. It includes tests for various filters such as Most popular, Lowest price, Highest price, and Newest to ensure they return the correct item count.

This step sets the initial condition that the user is on the products page of the website.

This action simulates the user clicking on a specific filter option, such as Most popular or Lowest price.

This action simulates the user selecting a gender filter, such as Male or Female.

This action simulates the user selecting a shoe size, such as 10.5 or 6.

This step verifies that the first sneaker displayed matches the expected sneaker for the given filter.
This step verifies that the total number of items displayed matches the expected item count.

Conclusion

Gherkin Scenario Outlines are essential for enhancing clarity and efficiency in your behavior-driven development (BDD) process. They allow for reusable scenarios with varying inputs, simplifying test case creation and promoting collaboration among team members. In the next guide, you’ll learn about Implementing Step Definitions, where we’ll connect your Gherkin scenarios to executable code.

Implementing Step Definitions

cucumber-guides-featured-image

Now is the time to create and implement our Step Definition Class in Cucumber. This critical step will ensure our test automation framework is robust and efficient. In this guide, we will walk you through the process of setting up your Step Definition Class, specifically focusing on creating a file to store your HomeStepDefs file within your project.

Setting Up Your Step Definition Class

To begin, navigate to the appropriate location in your project directory where you want to store your Step Definition files. It’s essential to keep your project well-organized, making it easier to maintain and scale as needed. In this case we’ll be storing our files in this location – src/test/java/com/kicksapp/stepDefs

cucumber-step- definitions-directory
Cucumber Step Definitions Directory
  1. IDE: Launch Eclipse and open your project to get started on your Gherkin test definitions.
  2. Directory: Navigate to the src/test/java/com/kicksapp/stepDefs/ directory, where your step definitions will be organized.
  3. Create a New File: In the stepDefs directory, right-click and choose [direction]New File[/direction] to create a new file named HomeStepDefs.java, which will house your Gherkin step definitions for the Home feature.
HomeStepDefs
src/test/java/kicksapp/stepDefs/HomeStepDefs.java

Convert Project to A Cucumber Project

Right-click on your project and select Configure Convert to Cucumber Project . This set is necessary so we can generate our gherkin snippets.

convert-to-cucumber-project
Converting Project To A Cucumber Project

Generate Gherkin Method Snippets

To generate the necessary Gherkin method snippets, run the home-screen.feature file:

  1. Run Feature File: Right-click on the home-screen.feature file and select [direction] Run As > Cucumber Feature[/direction].
  2. Review Snippets: Eclipse will execute the feature file, and if any step definitions are missing, it will generate method snippets for you. Copy these snippets into your HomeStepDefs.java class.
gherkin-generated-sample-snippets
Gherkin Generated Sample Snippets
Gherkin Method Snippets
@Given("the user is on the home screen")
public void the_user_is_on_the_home_screen() {
    // Write code here that turns the phrase above into concrete actions
    throw new io.cucumber.java.PendingException();
}

@When("the user clicks the {string} icon")
public void the_user_clicks_the_icon(String string) {
    // Write code here that turns the phrase above into concrete actions
    throw new io.cucumber.java.PendingException();
}

@Then("the {string} screen is displayed")
public void the_screen_is_displayed(String string) {
    // Write code here that turns the phrase above into concrete actions
    throw new io.cucumber.java.PendingException();
}

@When("the user clicks the {string} link")
public void the_user_clicks_the_link(String string) {
    // Write code here that turns the phrase above into concrete actions
    throw new io.cucumber.java.PendingException();
}

Now that we have our snippets, it’s time to add the necessary logic to each method to complete our HomeStepDefs class. This step is crucial as it bridges the gap between our feature files written in Gherkin and the actual automation code that interacts with our web application.

In the HomeStepDefs class, we initialize a WebDriver instance through the Hooks class, ensuring a consistent browser session. The testUrl variable holds the URL of our web application, setting the stage for user interaction scenarios.

HomeStepDefs – WebDriver
public class HomeStepDefs {
public WebDriver driver = Hooks.driver;
private final String testUrl = "https://jahmalrichard.github.io/kicks-flutter-web-app/";

Navigating to the Home Screen

The first step is to navigate the user to the home screen. Using the @Given annotation, we define the method the_user_is_on_the_home_screen. This method directs the browser to the specified URL and pauses for 2 seconds to ensure the page is fully loaded.

kicks-app-home-screen
Kicks App | Home Screen
@Given
@Given("the user is on the home screen")
public void the_user_is_on_the_home_screen() throws InterruptedException {
    driver.get(testUrl);
    Utils.wait(2);
}

Interacting with Icons

Next, we manage user interactions with icons on the home screen. The @When annotation is used to define the method the_user_clicks_the_icon. This method receives an icon name as a parameter, locates the corresponding icon using a CSS selector, and performs a click action.

find-and-click-login-icon
Find & Click The Login Icon
@When
@When("the user clicks the {string} icon")
public void the_user_clicks_the_icon(String iconName) {
    try {
        switch(iconName.toLowerCase()) {
            case "login": {
                WebElement loginIcon = driver.findElement(
                By.cssSelector("flt-semantics[aria-label=\"login-icon\"]"));
                loginIcon.click();
                Utils.wait(2);
                break;
            }
            default:
                System.err.println("The icon called '" + iconName + "' was not found. Try again.");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Verifying Screen Displays

After interacting with icons, it’s essential to verify that the correct screen is displayed. The @Then annotation defines the method the_screen_is_displayed, which checks for the presence of the Sign In button on the login screen to confirm successful navigation.

verify-that-the-sign-in-button-exist
Verify That The Sign In Button Exist
verify-the-products-page-is-displayed
Verifying That The Product Page Is Displayed
@Then
@Then("the {string} screen is displayed")
public void the_screen_is_displayed(String screenName) {
    try {
        switch(screenName.toLowerCase()) {
            case "login": {
                WebElement loginSignInButton = driver.findElement(By.cssSelector("flt-semantics[aria-label=\"Sign In\"]"));
                assert loginSignInButton.isDisplayed();
                Utils.wait(2);
                break;
            }
            case "products": {
                WebElement filterMostPopular = driver.findElement(By.cssSelector("flt-semantics[aria-label=\"Most popular\"]"));
                assert filterMostPopular.isDisplayed();
                Utils.wait(2);
                break;
            }
            default:
                System.err.println("The screen named '" + screenName + "' was not found. Try again.");
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Navigating via Links

Lastly, we enable users to click on various links within the application. The @When annotation is used again to define the method the_user_clicks_the_link, which handles click actions for specified links.

Tip: Navigating Links

This method is related to the second scenario, where we click on the Products link and verify that we’re on he Products screen.

user-clicks-the-products-link
User Clicks The Products Link
@When
@When("the user clicks the {string} link")
    public void the_user_clicks_the_link(String linkName) {
        try {
            switch(linkName.toLowerCase()) {
                case "products": {
                    WebElement productsNavLink = driver.findElement(
                    By.cssSelector("flt-semantics[aria-label=\"Products\"]"));
                    productsNavLink.click();
                    Utils.wait(2);
                    break;
                }
                default:
                    System.err.println("The link named '" + linkName + "' was not found. Try again.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Tip: HomeStepDefs

By integrating these methods into our HomeStepDefs class, each method is crafted to handle specific interactions and verifications, making our tests both comprehensive and easy to understand.

Conclusion

Now that we have a solid grasp of creating and managing step definitions, it’s time to elevate our Cucumber skills further. In next guide, we’ll delve into Understanding Cucumber Tags, a powerful feature that can enhance the flexibility and efficiency of your testing framework.

Understanding Cucumber Tags

cucumber-guides-featured-image

In this guide, you’ll learn how to use Cucumber tags and hooks to organize and manage your tests efficiently. Tags allow you to categorize your scenarios, and hooks provide a way to run code before or after scenarios.

Tags in Cucumber

Tags are a way to organize and control the execution of your tests. They allow you to group scenarios, features, or even specific steps, making it easier to manage large test suites. Tags are prefixed with @ and placed above the relevant Gherkin keyword.

 

Single Tag

A single tag, such as @smoketest or @ignore, is used to label a specific test scenario. For instance, @smoketest indicates a basic test run to check the essential functionality, while @ignore is used to exclude certain tests from execution.

Single Tag: @smoketest | @ignore
@smoketest
Scenario: Click the Login Icon
  Given the user is on the home screen
  When the user clicks the "login" icon
  Then the "Login" screen is displayed

@ignore
Scenario: Click the Products link
  Given the user is on the home screen
  When the user clicks the "Products" link
  Then the "Products" screen is displayed

Multiple Tags

Multiple tags, like @smoketest @critical, combine multiple categories, providing a more granular control over which tests to run. This combination might be used to run tests that are both part of the smoke test suite and critical for the application, ensuring that key functionalities are validated promptly.

Multiple Tags: @smoketest @critical
@smoketest @critical
Scenario: Click the Login Icon
  Given the user is on the home screen
  When the user clicks the "login" icon
  Then the "Login" screen is displayed

Creating a Test Runner

Create a test runner class in the src/test/java/com/kicksapp/runners directory. We’re going to name this class HomeScreenRunner.

creating-home-screen-runner-file
Creating Home Screen Runner File

Running Tests with Tags

To run tests with specific tags, use the @RunWith
and @CucumberOptions annotations in your test runner class.

The @CucumberOptions annotation is where you configure various aspects of your Cucumber tests. Here’s a breakdown of the options used in the snippet:

cucumber-runner-file-with-options
Cucumber Runner File With Options
HomeScreenRunner.class
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)
@CucumberOptions(
    features = "src/test/resources/features/home-screen.feature",
    glue = "com.kicksapp.stepdefs",
    tags = "@smoketest",
    plugin = {"pretty", "html:target/cucumber-reports.html"},
    monochrome = true
)
public class HomeScreenRunner {
}
  • features = "src/test/resources/features/home-screen.feature": This specifies the path to the feature files. Feature files contain scenarios written in Gherkin language, which Cucumber executes.
  • glue = "com.kicksapp.stepdefs": This option specifies the package where step definition methods are located. Step definitions are the actual code implementations of the steps described in the feature files.
  • tags = "@smoketest": Tags are used to filter which tests to run. In this case, only the scenarios tagged with @smoketest will be executed.
  • plugin = {"pretty", "html:target/cucumber-reports.html"}: This specifies the reporting plugins to use. The html plugin generates a simple html test report.
  • monochrome = true: This option makes the console output more readable by removing unnecessary characters and colors.

Tag Expressions

Cucumber supports tag expressions to combine multiple tags using logical operators:

The AND operator in Cucumber tag expressions is used to run scenarios that are tagged with multiple tags simultaneously. For instance, consider the tags @login and @critical. By using the expression @login and @critical, Cucumber will execute only those scenarios that are tagged with both @login and @critical. This is particularly useful when you need to focus on tests that are both essential and pertain to specific functionalities.
Tags: AND
@CucumberOptions(
    features = "src/test/resources/features/home-screen.feature",
    glue = "com.kicksapp.stepdefs",
    tags = "@login and @critical",
    plugin = {"pretty", "html:target/cucumber-reports.html"},
    monochrome = true
)
The OR operator broadens the scope by running scenarios that match any of the specified tags. For example, using @moketest or @critical will run all scenarios tagged with either @smoketest or @critical. This approach is beneficial when you want to cover a broader range of tests without being too restrictive, ensuring that all relevant functionalities are tested.
Tags: OR
@CucumberOptions(
    features = "src/test/resources/features/home-screen.feature",
    glue = "com.kicksapp.stepdefs",
    tags = "@smoketest or @critcal",
    plugin = {"pretty", "html:target/cucumber-reports.html"},
    monochrome = true
)
The NOT operator is employed to exclude specific tags from the test run. For example, the expression not @ignore will execute all scenarios except those tagged with @ignore. This is especially useful for excluding tests that are either known to fail, are under development, or are not currently relevant to the test cycle.
Tags: NOT
@CucumberOptions(
    features = "src/test/resources/features/home-screen.feature",
    glue = "com.kicksapp.stepdefs",
    tags = "@smoketest and not @ignore",
    plugin = {"pretty", "html:target/cucumber-reports.html"},
    monochrome = true
)

Conclusion

You’ve mastered the art of using tags. Tags allow you to categorize your scenarios, making it easier to run specific tests based on your needs. Whether you’re focusing on a particular feature or running regression tests, tags streamline the process, saving you valuable time.

Now that you are comfortable with tags, it’s time to start Understanding Cucumber Hooks.

Understanding Cucumber Hooks

cucumber-guides-featured-image

In this guide, you’ll learn how to use Cucumber hooks to streamline your testing process and make your scenarios more efficient. Cucumber hooks are blocks of code that run at various points in the Cucumber test cycle, allowing you to set up and tear down the test environment, manipulate data, and configure test settings dynamically. By mastering hooks, you can enhance your test suite’s maintainability and readability, ensuring that your tests run smoothly and reliably.

Hooks in Cucumber

Hooks are special blocks of code that run at specific points in the test execution lifecycle. They allow you to set up preconditions and postconditions for your tests. In Cucumber, hooks are defined using the @Before and @After annotations.

Types of Hooks

Before Hook

The @Before hook, as the name suggests, runs before each scenario. This means that any code you include in a @Before hook will execute before your test case starts. This is essential for preparing the test environment, ensuring that each test runs in a clean and consistent state. For instance, you might want to launch a browser, navigate to a specific URL, or initialize test data.

@Before Hook
public class Hooks {

public static WebDriver driver;

@Before
public void setup() {
	System.setProperty("webdriver.chrome.driver", "src/test/resources/driver/chromedriver");

	driver = new ChromeDriver();
	driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
	driver.manage().window().maximize();
}

After Hook

Among the different types of hooks, the @After hook plays a crucial role in ensuring your test scenarios are executed smoothly and efficiently. Specifically, the @After hook runs after each scenario, providing a perfect opportunity to perform cleanup tasks, release resources, or log information that helps in debugging and analysis.

@After Hook
@After
public void tearDown() {
  if (driver != null) {
    driver.quit();
    driver = null;
  }

BeforeStep

The @BeforeStep hook, as its name suggests, runs before each individual step in your test scenarios. This hook can be particularly useful for setting up preconditions or performing repetitive tasks that need to be executed before every step.

@BeforeStep Hook
@BeforeStep
public void beforeStep(Scenario scenario) {
    System.out.println("About to execute step: " + scenario.getName());
}

AfterStep

The @AfterStep hook in Cucumber is designed to run a block of code after every single step of your test scenario. This capability is essential for tasks such as taking screenshots after each step to help with debugging or logging detailed information about the execution of each step. Implementing the @AfterStep hook can significantly enhance the visibility and traceability of your tests, making it easier to identify where an issue occurred if a test fails.

@AfterStep Hook
@AfterStep
public void afterStep(Scenario scenario) {
	Utils.wait(3);
	final byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
	scenario.attach(screenshot, "image/png", "image");
}

Conditional Hooks

To further refine and control the execution of hooks, Cucumber provides the feature of conditional hooks with tags. Tags in Cucumber are metadata assigned to scenarios or feature files, and they can be used to conditionally apply hooks. For instance, if you have specific setup or teardown procedures that should only run for certain tests, you can tag those tests accordingly and define hooks that only trigger for those tags.
Conditional Tags
import io.cucumber.java.Before;
import io.cucumber.java.After;

public class Hooks {

  @Before("@login")
  public void beforeLogin() {
    // Code to run before scenarios tagged with @login
  }

  @After("@logout")
  public void afterLogout() {
    // Code to run after scenarios tagged with @logout
  }
}

Conclusion

Incorporating hooks into your Cucumber tests is a powerful way to maintain a stable test environment, enhancing the overall reliability of your test suite. With hooks, you gain precise control over your test execution process, ensuring each scenario begins and ends in a consistent state. This mastery can lead to more trustworthy and efficient testing, ultimately contributing to higher quality software. Now that you are comfortable with tags and hooks, it’s time to start Running Your Cucumber Tests & Generating Reports.

Running Cucumber Tests & Generating Reports

cucumber-guides-featured-image

Setting up Hooks and Tags in Cucumber is just the beginning of efficient test automation. Once your environment is configured, the next step is to explore the various methods available for executing your Cucumber scripts.Each method has its unique advantages and use cases. In this guide, we will delve into three primary ways to run your Cucumber tests:

  • The Feature File - This method is ideal for quickly running specific features during development.
  • JUnit Test - This method is suitable for developers looking to perform rapid testing of their scripts with minimal setup.
  • Maven using Terminal - This method is perfect for integrating into continuous integration/continuous deployment.

Running as a Cucumber Feature

The first method to execute your Cucumber script is directly from the feature file. This method is straightforward and does not consider tags.

running-as-a-cucumber-feature
Running As A Cucumber Feature
  • How to Execute: Right-click on the feature file and select
    Run As > Cucumber Feature.
  • Best Use Case: This method is ideal for quickly running specific features during development, allowing you to verify functionality without the need for additional configurations.

Running as a Cucumber Feature

This method does not allow for the use of tags, which can be limiting if you need to run specific subsets of tests.

Running as a JUnit Test

The second method involves running your Cucumber scripts using JUnit, which is great for quick testing.

running-as-a-junit-test
Running As A JUnit Test
  • How to Execute: Open the Runner File and select Run As > JUnit Test.
  • Best Use Case: This method is suitable for testers looking to perform rapid testing of their scripts with minimal setup.

Running as a JUnit Test

Primarily used within a local development setup and may not be suitable for larger, continuous integration environments.

Configuring Cucumber Options

One of the standout features of Cucumber is its ability to integrate with various plugins, which allows users to generate a variety of reports.

Common Plugin Options

 
  • html: This plugin generates a comprehensive HTML report, providing a clear and visually appealing overview of your test results.
  • json: The JSON plugin creates a structured JSON report, offering detailed insights that can be easily integrated into other tools or systems for further analysis.
  • junit: The JUnit plugin produces a standard JUnit XML report, ensuring compatibility with various testing frameworks and continuous integration tools.
  • extents adapter: This plugin generates a visually stunning HTML report with rich formatting and detailed analytics, making it easy to share and present your test outcomes.
CucumberOptions
@CucumberOptions(
        features = "src/test/resources/features",
        glue = "com.masteringqa.stepdefinitions",
        tags = "@smoketest",
        plugin = {},
        monochrome = true,

)

Generating Reports

Cucumber can generate various types of reports. The most commonly used are HTML and JSON reports.

HTML Report

HTML reports are user-friendly and provide a detailed overview of test scenarios, steps, and their outcomes.

HTML Report
@CucumberOptions(
        features = "src/test/resources/features",
        glue = "com.masteringqa.stepdefinitions",
        tags = "@smoketest",
        plugin = {"pretty","html:target/cucumber-reports.html"},
        monochrome = true,

)
example-of-the-html-report
Example: HTML Report

JSON Report

JSON reports are useful for integrating Cucumber test results with other tools, such as CI/CD pipelines or dashboards. These reports provide a structured format that can be easily parsed and processed.

JSON Reports
@CucumberOptions(
        features = "src/test/resources/features",
        glue = "com.masteringqa.stepdefinitions",
        tags = "@smoketest",
        plugin = {"pretty","json:target/cucumber-reports.json"}
        monochrome = true,

)
example-of-json-reports
Example: JSON Report

Extent HTML Report

The ExtentCucumberAdapter plugin is a highly versatile and essential tool for modern test reporting, seamlessly integrating with your testing pipeline to deliver a cutting-edge HTML reporting design. Its interactive, visually appealing format transforms test results into clear and actionable insights, making it indispensable for enhancing the efficiency and transparency of your testing processes.

Extent HTML Report
@CucumberOptions(
        features = "src/test/resources/features",
        glue = "com.masteringqa.stepdefinitions",
        tags = "@smoketest",
        plugin = {"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"},
        monochrome = true,
)
example-of-the-extent-html-report
Example: Extent HTML Report

Ensure you add the plugin to your runner before proceeding!

Once the plugin is added, execute the mvn test command to run your tests. After the tests complete, you can view the detailed report generated by the ExtentsCucumberAdapter.  This will also work for Running as a JUnit Test method.

Running from Terminal using Maven

The third method is running your scripts from the terminal using the mvn test command with the Surefire plugin, ideal for pipeline integration. In this scenario we’ll use the extents report.

running-the-test-using-maven-command-in-terminal
Running The Test Using Maven Command in Terminal
Terminal: mvn test
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-surefire-plugin</artifactId>
	<version>3.0.0-M5</