如何在Karate的.feature文件间复用JavaScript函数(不依赖外部JS文件)
Great question! In Karate, you absolutely can reuse JavaScript functions and code snippets across .feature files without relying on external JS files. I’ve used these approaches extensively in real-world testing workflows—let’s break them down:
The cleanest way is to centralize all reusable code in a dedicated utility .feature file. Think of it as your project’s internal function library.
Step 1: Define your shared functions in a utility file
Create something like utils.feature (place it in your test resources folder):
Feature: Reusable Utility Functions & Code Scenario: Define core helper functions # Calculate total price from a list of items * def calculateTotal = (items) => items.reduce((sum, item) => sum + item.price, 0) # Format dates to a readable string * def formatDate = (dateString) => new Date(dateString).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }) # Generate a random test user object * def generateTestUser = () => ({ id: karate.uuid(), name: `Test User ${karate.randomString(5)}`, email: `test-${karate.randomString(5)}@example.com` })
Step 2: Import and use these functions in other features
Use Karate’s call keyword to load the utility file into your target feature’s scope. You can do this in a Background section to make the functions available to all scenarios:
Feature: E-Commerce Checkout Tests Background: # Load shared utilities once for all scenarios in this feature * call read('classpath:utils.feature') Scenario: Verify cart total calculation * def cartItems = [{ price: 29.99 }, { price: 15.50 }, { price: 9.99 }] * def cartTotal = calculateTotal(cartItems) * match cartTotal == 55.48 Scenario: Create and validate a test user * def newUser = generateTestUser() * def createUserResponse = karate.post('/api/users', newUser) * match createUserResponse.status == 201 * match createUserResponse.body.email == newUser.email
If you only need specific functions (and want to avoid polluting the scope), you can assign the result of call to a variable and access functions via it:
* def utils = call read('classpath:utils.feature') * def formattedDate = utils.formatDate('2024-05-20')
karate.callSingle for Singleton-Style Reuse If you want your utility functions to be loaded once per test run (instead of once per feature/scenario), use karate.callSingle instead of call. This is ideal for heavyweight setup or functions that don’t need to be reinitialized:
Background: # Load utilities once globally for all tests * karate.callSingle('classpath:utils.feature')
For more targeted reuse (like a specific setup or validation flow), you can define named scenarios in your utility file and call only that scenario when needed.
Example utility file snippet:
Scenario: Setup test environment * def baseUrl = karate.properties['api.base.url'] * karate.configure('baseUrl', baseUrl) * def authToken = karate.call('classpath:auth.feature').token * karate.configure('headers', { Authorization: `Bearer ${authToken}` })
Call just this scenario in another feature:
Feature: Product API Tests Background: # Run only the setup scenario from utils * call read('classpath:utils.feature')['Setup test environment'] Scenario: Fetch product details * def productResponse = karate.get('/api/products/123') * match productResponse.status == 200
Pro Tip: Pass Parameters to Reusable Code
If your functions or scenarios need dynamic values, you can pass parameters when calling the utility file:
# In utils.feature Scenario: Calculate discounted total * def discountPercent = karate.get('discount') || 10 # Default to 10% if no discount is passed * def calculateDiscountedTotal = (items) => calculateTotal(items) * (1 - discountPercent / 100) # In your target feature * call read('classpath:utils.feature') { discount: 15 } # Pass 15% discount * def discountedTotal = calculateDiscountedTotal(cartItems)
内容的提问来源于stack exchange,提问作者Aneesh Goel

