Skip to main content

ADVANCED

Java API

Karate provides a comprehensive Java API for programmatic test execution, framework integration, and advanced Java interoperability.

Programmatic Test Execution

Execute Karate tests from Java code for custom test runners and CI/CD integration.

Basic Execution

import com.intuit.karate.Results;
import com.intuit.karate.Runner;

public class TestRunner {
public static void main(String[] args) {
// Execute all features in classpath
Results results = Runner.path("classpath:tests")
.parallel(5);

// Check results
if (results.getFailCount() > 0) {
System.err.println("Tests failed: " + results.getFailCount());
System.exit(1);
}
}
}
```gherkin

### Runner Builder API

```java
Results results = Runner.builder()
.path("classpath:features")
.tags("@smoke", "~@ignore")
.karateEnv("staging")
.systemProperty("api.key", "secret123")
.outputCucumberJson(true)
.outputJunitXml(true)
.parallel(10);

// Access detailed results
System.out.println("Scenarios run: " + results.getScenarioCount());
System.out.println("Scenarios passed: " + results.getPassCount());
System.out.println("Time taken: " + results.getElapsedTime() + " ms");
```gherkin

### Feature-Specific Execution

```java
import com.intuit.karate.core.Feature;
import com.intuit.karate.core.FeatureRuntime;

// Load specific feature
Feature feature = Feature.read("classpath:users/create-user.feature");

// Execute with custom configuration
Map<String, Object> args = new HashMap<>();
args.put("username", "testuser");
args.put("env", "qa");

FeatureRuntime runtime = FeatureRuntime.of(feature, args);
runtime.run();

// Get results
if (runtime.result.isFailed()) {
runtime.result.getErrors().forEach(System.err::println);
}
```gherkin

## Java Function References

Create reusable Java utilities for Karate tests with proper multi-threading support.

### Thread-Safe Java Functions

```java
package com.example.karate;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class TestUtils {
// Thread-safe counter
private static final AtomicInteger counter = new AtomicInteger(0);

// Thread-safe cache
private static final Map<String, Object> cache = new ConcurrentHashMap<>();

// Static factory method for Karate
public static TestUtils create() {
return new TestUtils();
}

public int getNextId() {
return counter.incrementAndGet();
}

public void cacheValue(String key, Object value) {
cache.put(key, value);
}

public Object getCachedValue(String key) {
return cache.get(key);
}

// Complex data processing
public Map<String, Object> processData(Map<String, Object> input) {
Map<String, Object> result = new HashMap<>(input);
result.put("processedAt", System.currentTimeMillis());
result.put("threadId", Thread.currentThread().getId());
return result;
}
}
```gherkin

### Using Java Functions in Karate

```gherkin
Feature: Java function usage

Background:
# Create instance using factory method
* def TestUtils = Java.type('com.example.karate.TestUtils')
* def utils = TestUtils.create()

Scenario: Thread-safe operations
# Get unique IDs
* def id1 = utils.getNextId()
* def id2 = utils.getNextId()
* assert id2 == id1 + 1

# Cache operations
* utils.cacheValue('token', 'abc123')
* def cached = utils.getCachedValue('token')
* match cached == 'abc123'

# Process data
* def input = { name: 'test', value: 100 }
* def output = utils.processData(input)
* match output contains { name: 'test', value: 100, processedAt: '#number' }
```gherkin

### Java Database Integration

```java
package com.example.karate;

import java.sql.*;
import java.util.*;

public class DatabaseUtils {
private final String jdbcUrl;
private final String username;
private final String password;

public DatabaseUtils(Map<String, Object> config) {
this.jdbcUrl = (String) config.get("url");
this.username = (String) config.get("username");
this.password = (String) config.get("password");
}

public List<Map<String, Object>> query(String sql) {
List<Map<String, Object>> results = new ArrayList<>();

try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {

ResultSetMetaData metadata = rs.getMetaData();
int columnCount = metadata.getColumnCount();

while (rs.next()) {
Map<String, Object> row = new HashMap<>();
for (int i = 1; i <= columnCount; i++) {
row.put(metadata.getColumnName(i), rs.getObject(i));
}
results.add(row);
}
} catch (SQLException e) {
throw new RuntimeException("Database query failed", e);
}

return results;
}

public int update(String sql) {
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
Statement stmt = conn.createStatement()) {
return stmt.executeUpdate(sql);
} catch (SQLException e) {
throw new RuntimeException("Database update failed", e);
}
}

public void cleanupTestData(String tableName, String condition) {
String sql = "DELETE FROM " + tableName + " WHERE " + condition;
update(sql);
}
}
```gherkin

### Using Database Utils

```gherkin
Feature: Database integration

Background:
* def dbConfig = { url: 'jdbc:mysql://localhost:3306/test', username: 'root', password: 'pass' }
* def DbUtils = Java.type('com.example.karate.DatabaseUtils')
* def db = new DbUtils(dbConfig)

Scenario: Database operations
# Query data
* def users = db.query("SELECT * FROM users WHERE active = true")
* match users[0] contains { id: '#number', username: '#string' }

# Update data
* def updateCount = db.update("UPDATE users SET last_login = NOW() WHERE id = 1")
* assert updateCount == 1

# Cleanup
* db.cleanupTestData('test_data', "created_at < DATE_SUB(NOW(), INTERVAL 1 DAY)")
```gherkin

## Custom Karate Extensions

Create custom extensions to enhance Karate functionality.

### Custom Hook Implementation

```java
package com.example.karate;

import com.intuit.karate.RuntimeHook;
import com.intuit.karate.core.ScenarioRuntime;
import com.intuit.karate.core.StepRuntime;

public class CustomHook implements RuntimeHook {

@Override
public boolean beforeScenario(ScenarioRuntime sr) {
System.out.println("Starting scenario: " + sr.scenario.getName());
// Add custom setup
sr.engine.setVariable("startTime", System.currentTimeMillis());
return true; // Continue execution
}

@Override
public void afterScenario(ScenarioRuntime sr) {
long startTime = (Long) sr.engine.getVariable("startTime");
long duration = System.currentTimeMillis() - startTime;
System.out.println("Scenario completed in: " + duration + " ms");

// Custom reporting
if (sr.result.getFailedStep() != null) {
notifyFailure(sr);
}
}

@Override
public boolean beforeStep(StepRuntime sr) {
// Log each step
System.out.println("Executing: " + sr.step.getText());
return true;
}

private void notifyFailure(ScenarioRuntime sr) {
// Send notification, update dashboard, etc.
System.err.println("FAILED: " + sr.scenario.getName());
}
}
```gherkin

### Using Custom Hooks

```java
Results results = Runner.builder()
.path("classpath:features")
.hook(new CustomHook())
.parallel(5);
```gherkin

### Custom Report Generator

```java
package com.example.karate;

import com.intuit.karate.Results;
import com.intuit.karate.core.ScenarioResult;
import java.io.FileWriter;
import java.io.IOException;

public class CustomReporter {

public static void generateReport(Results results, String outputPath) {
try (FileWriter writer = new FileWriter(outputPath)) {
writer.write("# Test Execution Report\n\n");
writer.write("## Summary\n");
writer.write("- Total Scenarios: " + results.getScenarioCount() + "\n");
writer.write("- Passed: " + results.getPassCount() + "\n");
writer.write("- Failed: " + results.getFailCount() + "\n");
writer.write("- Duration: " + results.getElapsedTime() + " ms\n\n");

if (results.getFailCount() > 0) {
writer.write("## Failed Scenarios\n");
for (ScenarioResult sr : results.getScenarioResults()) {
if (sr.getFailedStep() != null) {
writer.write("- " + sr.getScenario().getName() + "\n");
writer.write(" - Error: " + sr.getError().getMessage() + "\n");
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
```gherkin

## Integration Examples

### Spring Boot Integration

```java
@RestController
@RequestMapping("/api/tests")
public class KarateTestController {

@PostMapping("/run")
public TestResults runTests(@RequestBody TestRequest request) {
Results results = Runner.builder()
.path("classpath:" + request.getFeaturePath())
.tags(request.getTags())
.karateEnv(request.getEnvironment())
.parallel(request.getParallelCount())
.build();

return TestResults.builder()
.passed(results.getPassCount())
.failed(results.getFailCount())
.duration(results.getElapsedTime())
.build();
}
}
```gherkin

### TestNG Integration

```java
import org.testng.annotations.Test;
import org.testng.Assert;

public class KarateTestNGRunner {

@Test(groups = {"smoke"})
public void runSmokeTests() {
Results results = Runner.path("classpath:smoke")
.tags("@smoke")
.parallel(5);

Assert.assertEquals(results.getFailCount(), 0,
"Smoke tests failed: " + results.getErrorMessages());
}

@Test(groups = {"regression"})
public void runRegressionTests() {
Results results = Runner.path("classpath:regression")
.tags("@regression", "~@ignore")
.parallel(10);

Assert.assertEquals(results.getFailCount(), 0);
}
}
```gherkin

## Performance Optimization

### Parallel Execution Strategy

```java
public class OptimizedRunner {

public static Results runWithOptimalParallelism() {
int availableProcessors = Runtime.getRuntime().availableProcessors();
int optimalThreads = Math.min(availableProcessors * 2, 16);

return Runner.builder()
.path("classpath:features")
.parallel(optimalThreads)
.build();
}

public static Results runWithCustomThreadPool() {
ExecutorService executor = Executors.newFixedThreadPool(10);

try {
return Runner.builder()
.path("classpath:features")
.executor(executor)
.build();
} finally {
executor.shutdown();
}
}
}
```gherkin

## Best Practices

### Resource Management

```java
public class ResourceManager {
private static final ThreadLocal<Connection> connectionHolder = new ThreadLocal<>();

public static Connection getConnection() {
Connection conn = connectionHolder.get();
if (conn == null) {
conn = createConnection();
connectionHolder.set(conn);
}
return conn;
}

public static void cleanup() {
Connection conn = connectionHolder.get();
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// Log error
}
connectionHolder.remove();
}
}
}
```gherkin

### Error Handling

```java
public class SafeTestUtils {

public static Object safeExecute(Callable<Object> task, Object defaultValue) {
try {
return task.call();
} catch (Exception e) {
System.err.println("Task execution failed: " + e.getMessage());
return defaultValue;
}
}

public static Map<String, Object> wrapResponse(Callable<Object> task) {
Map<String, Object> response = new HashMap<>();
try {
response.put("success", true);
response.put("data", task.call());
} catch (Exception e) {
response.put("success", false);
response.put("error", e.getMessage());
}
return response;
}
}
```gherkin

## Next Steps

- Learn about [Hooks and Lifecycle](/docs/advanced/hooks) for test lifecycle management
- Explore [Code Reuse](/docs/reusability/code-reuse) patterns
- Review [Parallel Execution](/docs/running-tests/parallel-execution) strategies