Pages

Integration of Karate API with JUnit 4

  

Integrating JUnit 4 with Karate API

Karate is a powerful testing framework based on BDD (Behavior Driven Development), especially useful for testing web services and APIs. It uses Gherkin syntax (like Cucumber) and can be integrated with JUnit 4 for test execution.


Step-by-Step Integration of Karate with JUnit 4


Step 1: Add Dependencies


<dependencies>
    <!-- Karate Core -->
    <dependency>
        <groupId>com.intuit.karate</groupId>
        <artifactId>karate-junit4</artifactId>
        <version>1.4.1</version> <!-- or latest stable version -->
        <scope>test</scope>
    </dependency>

    <!-- For Assertions and Test Reporting -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>




Step 2: Create Feature File

Create a file named sample.feature under:


src/test/java/examples




Feature file:

Feature: Sample API Test

  Scenario: Verify GET request
    Given url 'https://jsonplaceholder.typicode.com/posts/1'
    When method get
    Then status 200
    And match response.userId == 1


Step 3: Create JUnit 4 Test Runner

Create a Java class to run the above feature with JUnit 4.

src/test/java/examples/SampleRunnerTest.java:


package examples;

import com.intuit.karate.junit4.Karate;
import org.junit.runner.RunWith;

@RunWith(Karate.class)
public class SampleRunnerTest {
    // No need to write any code inside
}

This class tells JUnit 4 to use Karate as the test runner and will automatically find the .feature file in the same package.


Step 4: Run the Test

  • Right-click on SampleRunnerTest.java and choose Run As → JUnit Test

  • Or run via Maven:


mvn test



Step 5: View Reports

Karate automatically generates reports in target/karate-reports:

  • karate-summary.html

  • karate.log

  • karate-report.html




Optional: Run All Feature Files in a Folder

package examples;

import com.intuit.karate.junit4.Karate;
import org.junit.runner.RunWith;

@RunWith(Karate.class)
public class AllTests {
    // This will run all *.feature files in this package
}




Benefits of Karate + JUnit 4 Integration


FeatureDescription
BDD SyntaxSimple, readable Gherkin language
JUnit CompatibilityEasily integrates into CI/CD
Rich ReportingAuto HTML & JSON reports
No Java Code NeededScenarios are defined in .feature files

Test Runner in Cucumber using JUnit

  

To implement a Test Runner class with JUnit in Cucumber, you need to create a class annotated with @RunWith and @CucumberOptions. This class serves as the entry point for running your Cucumber test scenarios written in .feature files using JUnit.


Below are the steps to implement Test runner in Cucumber with Testng


1. Add Maven Dependencies

Make sure your pom.xml contains these dependencies:

<dependencies>
    <!-- Cucumber JUnit -->
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-junit</artifactId>
        <version>7.11.1</version>
        <scope>test</scope>
    </dependency>

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

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


 

2. Create Feature File

Example: src/test/resources/features/login.feature

Feature: Login functionality

  Scenario: Valid login
    Given user is on login page
    When user enters valid username and password
    Then user is navigated to the homepage



3. Create Step Definition File

Example: src/test/java/stepdefinitions/LoginSteps.java

package stepdefinitions;

import io.cucumber.java.en.*;

public class LoginSteps {

    @Given("user is on login page")
    public void user_is_on_login_page() {
        System.out.println("User is on login page");
    }

    @When("user enters valid username and password")
    public void user_enters_valid_username_and_password() {
        System.out.println("User enters credentials");
    }

    @Then("user is navigated to the homepage")
    public void user_is_navigated_to_the_homepage() {
        System.out.println("User navigated to homepage");
    }
}



4. Create Test Runner Class

Example: src/test/java/testrunner/TestRunner.java

package testrunner;

import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)  // Tells JUnit to run Cucumber tests
@CucumberOptions(
    features = "src/test/resources/features", // path to feature files
    glue = "stepdefinitions",                // package of step definitions
    plugin = {"pretty", "html:target/cucumber-reports.html"},
    monochrome = true
)
public class TestRunner {
    // No code needed here
}



5. Run the Test

You can run the TestRunner.java file like a normal JUnit test class. Cucumber will pick the .feature files and corresponding step definitions.



Important Points:

ComponentDescription
@RunWith(Cucumber.class)Instructs JUnit to use Cucumber's test runner
@CucumberOptionsProvides feature path, glue (steps), plugin, formatting
featuresPath to .feature files
gluePackage containing step definition files
pluginReporting output (HTML, JSON, etc.)
monochromeMakes console output more readable

How to execute Parallel Test Cases in Appium with JUnit for Android Apps

  


To execute parallel test cases in Appium with JUnit for Android apps, you need to:

  • Set up multiple Android devices/emulators.
  • Assign unique ports and capabilities to each device.
  • Use JUnit's @Parameterized or a custom parallel runner.
  • Launch tests in parallel threads.



Prerequisites

  • Java (JDK 11+)

  • Appium server installed

  • Android SDK with AVDs or real devices

  • Eclipse or IntelliJ IDE

  • Appium Java client dependency in your Maven pom.xml:





Maven Dependency:

<dependency>
  <groupId>io.appium</groupId>
  <artifactId>java-client</artifactId>
  <version>9.0.0</version>
</dependency>






Step-by-step Implementation

1. Create a Device Configuration Class

public class DeviceConfig {
    public String deviceName;
    public String udid;
    public String platformVersion;
    public int systemPort;
    public int appiumPort;

    public DeviceConfig(String deviceName, String udid, String platformVersion, int systemPort, int appiumPort) {
        this.deviceName = deviceName;
        this.udid = udid;
        this.platformVersion = platformVersion;
        this.systemPort = systemPort;
        this.appiumPort = appiumPort;
    }
}






2. Create a Base Test Class to Setup Driver


public class BaseTest {
    protected AndroidDriver<MobileElement> driver;
    protected DeviceConfig device;

    public void setUp(DeviceConfig device) throws MalformedURLException {
        this.device = device;
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "Android");
        caps.setCapability("deviceName", device.deviceName);
        caps.setCapability("udid", device.udid);
        caps.setCapability("platformVersion", device.platformVersion);
        caps.setCapability("automationName", "UiAutomator2");
        caps.setCapability("systemPort", device.systemPort);
        caps.setCapability("app", System.getProperty("user.dir") + "/apps/yourapp.apk");

        driver = new AndroidDriver<>(new URL("http://127.0.0.1:" + device.appiumPort + "/wd/hub"), caps);
    }

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






3. Define Your Test Class With @RunWith(Parameterized.class)


@RunWith(Parameterized.class)
public class ParallelAppiumTest extends BaseTest {

    @Parameterized.Parameters
    public static Collection<DeviceConfig> devices() {
        return Arrays.asList(
            new DeviceConfig("emulator-5554", "emulator-5554", "11", 8200, 4723),
            new DeviceConfig("emulator-5556", "emulator-5556", "11", 8201, 4725)
        );
    }

    private DeviceConfig config;

    public ParallelAppiumTest(DeviceConfig config) {
        this.config = config;
    }

    @Before
    public void init() throws Exception {
        setUp(config);
    }

    @Test
    public void sampleTest() {
        System.out.println("Running test on: " + config.deviceName);
        // Your test code here
    }

    @After
    public void cleanup() {
        tearDown();
    }
}






Step 4: Start Multiple Appium Servers

Start different Appium servers on different ports manually or via command line:


appium -p 4723 --default-capabilities '{"systemPort": 8200}'
appium -p 4725 --default-capabilities '{"systemPort": 8201}'

Or use AppiumServiceBuilder from Java code to start servers dynamically (optional).

JUnit by default runs parameterized tests sequentially. To achieve true parallel execution, use JUnit Parallel Computer or a custom test runner like JUnitParams + multithreading.




Things to Remember:

  • Always assign unique systemPort and Appium server port for each device.
  • Don’t reuse driver objects across threads.
  • Avoid shared static variables unless they are synchronized.
  • You can scale it up using a Grid or Appium with Docker.

How to execute Parallel Test Cases in Appium with JUnit for IOS Apps

 


1. Prerequisites

  • Xcode installed (with WebDriverAgent setup)

  • Appium installed and running

  • iOS devices or simulators connected and available

  • Maven project with dependencies set up

  • iOS app (.ipa or .app)

  • Java 11+ and JUnit 5 recommended

  • Unique udid and wdaLocalPort for each device






Maven Dependencies


<dependencies>
    <dependency>
        <groupId>io.appium</groupId>
        <artifactId>java-client</artifactId>
        <version>8.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.9.3</version>
    </dependency>
</dependencies>





3. Create a Base Test Class

This handles session setup for each iOS device.



public class BaseIOSDriver {

    protected IOSDriver<MobileElement> driver;

    public IOSDriver<MobileElement> createDriver(String udid, int port, int wdaPort) {
        try {
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability("platformName", "iOS");
            caps.setCapability("automationName", "XCUITest");
            caps.setCapability("udid", udid);
            caps.setCapability("deviceName", "iPhone");
            caps.setCapability("app", "/path/to/your.app");
            caps.setCapability("wdaLocalPort", wdaPort); // Must be unique
            caps.setCapability("noReset", true);

            URL appiumServer = new URL("http://localhost:" + port + "/wd/hub");
            driver = new IOSDriver<>(appiumServer, caps);
            return driver;
        } catch (Exception e) {
            throw new RuntimeException("Driver creation failed: " + e.getMessage());
        }
    }
}





4. Write Test Class for Each Device

You can use threads or @ParameterizedTest with parallel configuration.


public class ParallelIOSTest1 extends BaseIOSDriver {

    @Test
    public void testDevice1() {
        IOSDriver<MobileElement> driver = createDriver("DEVICE_UDID_1", 4723, 8100);
        // Your test steps
        System.out.println("Running on Device 1");
        driver.quit();
    }
}



public class ParallelIOSTest2 extends BaseIOSDriver {

    @Test
    public void testDevice2() {
        IOSDriver<MobileElement> driver = createDriver("DEVICE_UDID_2", 4725, 8200);
        // Your test steps
        System.out.println("Running on Device 2");
        driver.quit();
    }
}





5. Enable Parallel Execution in Maven

Create a junit-platform.properties file inside src/test/resources/:



junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent





6. Run Tests with Maven

mvn test



Or, run specific classes in parallel:


mvn -Dtest=ParallelIOSTest1,ParallelIOSTest2 test





Things to Remember:
  • Each device needs its own wdaLocalPort

  • Use Appium servers on different ports (47234725, etc.)

  • Consider running separate Appium instances for each device:

appium -p 4723 --webdriveragent-port 8100
appium -p 4725 --webdriveragent-port 8200

Page Object Model with Appium, Cucumber, and JUnit for Android App

 


Below is the code for page object model (POM) with Appium, Cucumber and Junit for Android app. Please have a look.


Maven Dependencies:


<dependencies>
    <!-- Appium -->
    <dependency>
        <groupId>io.appium</groupId>
        <artifactId>java-client</artifactId>
        <version>8.3.0</version>
    </dependency>

    <!-- Cucumber -->
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-java</artifactId>
        <version>7.11.2</version>
    </dependency>
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-junit</artifactId>
        <version>7.11.2</version>
        <scope>test</scope>
    </dependency>

    <!-- JUnit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
    </dependency>
</dependencies>




Base Class for Appium Driver (BaseTest.java)


package utilities;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.MobileElement;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.net.URL;

public class BaseTest {
    public static AndroidDriver<MobileElement> driver;

    public void initializeDriver() throws Exception {
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("platformName", "Android");
        caps.setCapability("deviceName", "emulator-5554"); // change as per your device
        caps.setCapability("appPackage", "com.example.app");
        caps.setCapability("appActivity", "com.example.app.MainActivity");
        caps.setCapability("automationName", "UiAutomator2");

        driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), caps);
    }

    public void quitDriver() {
        if (driver != null) {
            driver.quit();
        }
    }
}





Cucumber Feature File (login.feature)


Feature: Login

  Scenario: Successful login
    Given App is launched
    When I login with valid credentials
    Then I should be navigated to the home page





Step Definitions (LoginSteps.java)


package stepDefinitions;

import io.cucumber.java.en.*;
import pages.LoginPage;
import utilities.BaseTest;

public class LoginSteps extends BaseTest {
    LoginPage loginPage;

    @Given("App is launched")
    public void app_is_launched() throws Exception {
        initializeDriver();
        loginPage = new LoginPage(driver);
    }

    @When("I login with valid credentials")
    public void i_login_with_valid_credentials() {
        loginPage.login("admin", "admin123");
    }

    @Then("I should be navigated to the home page")
    public void i_should_be_navigated_to_the_home_page() {
        // Add assertion logic or verification here
    }
}





Page Class using Page Object Model (LoginPage.java)


package pages;

import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;

public class LoginPage {
    AndroidDriver<MobileElement> driver;

    public LoginPage(AndroidDriver<MobileElement> driver) {
        this.driver = driver;
    }

    public MobileElement getUsernameField() {
        return driver.findElementById("com.example.app:id/username");
    }

    public MobileElement getPasswordField() {
        return driver.findElementById("com.example.app:id/password");
    }

    public MobileElement getLoginButton() {
        return driver.findElementById("com.example.app:id/login");
    }

    public void login(String username, String password) {
        getUsernameField().sendKeys(username);
        getPasswordField().sendKeys(password);
        getLoginButton().click();
    }
}






Cucumber Hooks (Hooks.java)


package utilities;

import io.cucumber.java.After;
import io.cucumber.java.Before;

public class Hooks extends BaseTest {

    @Before
    public void setup() throws Exception {
        initializeDriver();
    }

    @After
    public void tearDown() {
        quitDriver();
    }
}






Test Runner (TestRunner.java)


package runners;

import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;

@RunWith(Cucumber.class)
@CucumberOptions(
        features = "src/test/resources/features",
        glue = {"stepDefinitions", "utilities"},
        plugin = {"pretty", "html:target/cucumber-report.html"},
        monochrome = true
)
public class TestRunner {
}