com um clique
network-tests
// Use when writing NetworkRule integration tests in stripe-android — covers testBodyFromFile, inline JSON modification, request matchers, and fixture patterns
// Use when writing NetworkRule integration tests in stripe-android — covers testBodyFromFile, inline JSON modification, request matchers, and fixture patterns
Use when writing Compose UI tests in stripe-android — covers composeRule setup, Robolectric annotations, node assertions, and test tag patterns
Use when writing or structuring unit tests in stripe-android — covers runScenario pattern, fakes, Turbine Flow testing, and Truth assertions
Use when writing or running Paparazzi screenshot tests in stripe-android — covers PaparazziRule setup, recording/verifying commands, and test structure
Use when creating a fake test implementation in stripe-android — covers FakeClassName pattern, Turbine call tracking, ViewActionRecorder, and ensureAllEventsConsumed validation
| name | network-tests |
| description | Use when writing NetworkRule integration tests in stripe-android — covers testBodyFromFile, inline JSON modification, request matchers, and fixture patterns |
For instrumentation tests that need mocked network responses, use NetworkRule (from network-testing module) with testBodyFromFile. JSON fixture files live in the module's src/androidTest/resources/ directory (e.g., paymentsheet/src/androidTest/resources/checkout-session-init.json) and are resolved by filename from the resources root.
@RunWith(AndroidJUnit4::class)
internal class MyFeatureTest {
@get:Rule
val testRules: TestRules = TestRules.create()
private val networkRule = testRules.networkRule
@Test
fun testSomething() = runPaymentSheetTest(
networkRule = networkRule,
resultCallback = ::assertCompleted,
) { testContext ->
networkRule.enqueue(requestMatcher) { response ->
response.testBodyFromFile("my-fixture.json")
}
// ... test actions ...
}
}
When a test needs a modified JSON response, use the testBodyFromFile lambda to modify the base fixture inline — do NOT create a separate JSON file for each variation.
// GOOD: Modify the base fixture inline
networkRule.checkoutInit { response ->
response.testBodyFromFile("checkout-session-init.json") { json ->
json.put("customer_email", "session@example.com")
}
}
// BAD: Creating checkout-session-init-with-email.json with one field different
networkRule.checkoutInit { response ->
response.testBodyFromFile("checkout-session-init-with-email.json")
}
This keeps the fixture set minimal and makes the test-specific modifications explicit at the call site.
The lambda receives a JSONObject — use standard org.json methods to add or modify fields:
networkRule.checkoutInit { response ->
response.testBodyFromFile("checkout-session-init.json") { json ->
json.put("customer", JSONObject("""
{
"id": "cus_12345",
"payment_methods": [],
"can_detach_payment_method": true
}
""".trimIndent()))
json.put("customer_managed_saved_payment_methods_offer_save", JSONObject("""
{"enabled": true, "status": "not_accepted"}
""".trimIndent()))
}
}
For nested modifications, chain getJSONObject():
response.testBodyFromFile("checkout-session-init.json") { json ->
json.getJSONObject("server_built_elements_session_params")
.getJSONObject("deferred_intent")
.put("setup_future_usage", "off_session")
}
When multiple tests share the same JSON modification, extract the lambda as a parameter:
private fun runMyTest(
jsonModifier: (JSONObject) -> Unit = {},
) = runPaymentSheetTest(networkRule = networkRule, resultCallback = ::assertCompleted) { testContext ->
networkRule.checkoutInit { response ->
response.testBodyFromFile("checkout-session-init.json", jsonModifier)
}
// ... shared test logic ...
}
@Test
fun testWithSfu() = runMyTest { json ->
json.getJSONObject("server_built_elements_session_params")
.getJSONObject("deferred_intent")
.put("setup_future_usage", "off_session")
}
| Signature | Use when |
|---|---|
testBodyFromFile("file.json") | No modifications needed |
testBodyFromFile("file.json") { json -> ... } | Modifying JSON fields inline |
testBodyFromFile("file.json", replacements) | String-level find/replace with ResponseReplacement |
Use RequestMatchers (from com.stripe.android.networktesting.RequestMatchers) to validate request body parameters. Import the matchers you need statically:
import com.stripe.android.networktesting.RequestMatchers.bodyPart
import com.stripe.android.networktesting.RequestMatchers.hasBodyPart
import com.stripe.android.networktesting.RequestMatchers.not
networkRule.checkoutConfirm(
bodyPart("expected_amount", "5099"),
not(hasBodyPart("save_payment_method")),
) { response ->
response.testBodyFromFile("checkout-session-confirm.json")
}
bodyPart(), hasBodyPart(), and query(name, value) auto-decode both the matcher arguments and the request body before comparing. Use plain readable strings — urlEncode() is unnecessary:
// Keys with brackets and values with special characters — just use plain strings
bodyPart("billing_details[email]", "user@example.com")
bodyPart("billing_details[address][line1]", "123 Main St")
bodyPart("payment_method_data[allow_redisplay]", "unspecified")
// urlEncode() still works (backward compatible) but is unnecessary
// bodyPart(urlEncode("billing_details[email]"), urlEncode("user@example.com"))
When a request doesn't match a mock, the error message shows per-matcher diagnostics with the nearest-miss mock:
POST https://localhost/v1/payment_intents/pi_123/confirm
Body params: {billing_details[email]=actual@test.com, payment_method=pm_123}
Nearest mock: composite(path(/v1/confirm), bodyPart(billing_details[email], expected@test.com))
+ PASS: path(/v1/confirm)
+ PASS: method(POST)
- FAIL: bodyPart(billing_details[email], expected@test.com)
See PaymentSheetBillingConfigurationTest.kt for more examples.