Q18 of 40 · Karate
How would you mock a third-party dependency in a Karate test?
Short answer
Short answer: Start a Karate Mock Server on a known port before the suite, configure your service under test to call that port via karate-config.js or a system property, and define stub scenarios in the mock feature using pathMatches and methodIs predicates. Stop the server in an @AfterAll hook.
Detail
The flow is: test starts mock → configures service to call mock URL → test runs → mock intercepts service's outbound calls → test verifies the service's response.
Step 1 — write the mock feature:
Feature: Email service mock
Scenario: pathMatches('/email/send') && methodIs('post')
* def responseStatus = 202
* def response = { messageId: 'mock-msg-1', queued: true }
Scenario: pathMatches('/email/send') && methodIs('post')
&& request.to contains 'blocked@'
* def responseStatus = 422
* def response = { error: 'recipient blocked' }
Step 2 — start it in @BeforeAll:
emailMock = Karate.startMock("classpath:mocks/email-service.feature").port(8888);
System.setProperty("email.service.url", "http://localhost:8888");
Step 3 — karate-config.js picks it up:
var emailUrl = karate.properties['email.service.url'] || java.lang.System.getenv('EMAIL_SERVICE_URL');
return { emailServiceUrl: emailUrl };
Conditional stub responses: Karate Mock's scenario matching is evaluated top-to-bottom — add conditions to the Scenario line to return different responses for different request payloads (e.g., blocked recipients return 422).
// EXAMPLE
mocks/sms-gateway.feature
Feature: SMS gateway mock
# Happy path — all phone numbers except +1999
Scenario: pathMatches('/sms/send') && methodIs('post') && request.phone != '+19995551234'
* def responseStatus = 200
* def response = { messageId: '#(karate.uuid())', status: 'QUEUED' }
# Simulated carrier rejection for specific number
Scenario: pathMatches('/sms/send') && methodIs('post') && request.phone == '+19995551234'
* def responseStatus = 422
* def response = { error: 'CARRIER_REJECTED', phone: '#(request.phone)' }
# Catch-all for unexpected paths
Scenario:
* def responseStatus = 404
* def response = { error: 'not found in mock' }