con un clic
create-fake
// Use when creating a fake test implementation in stripe-android — covers FakeClassName pattern, Turbine call tracking, ViewActionRecorder, and ensureAllEventsConsumed validation
// Use when creating a fake test implementation in stripe-android — covers FakeClassName pattern, Turbine call tracking, ViewActionRecorder, and ensureAllEventsConsumed validation
| name | create-fake |
| description | Use when creating a fake test implementation in stripe-android — covers FakeClassName pattern, Turbine call tracking, ViewActionRecorder, and ensureAllEventsConsumed validation |
This skill describes how to create fake implementations for testing in the Stripe Android SDK. The codebase strongly prefers fakes over mocks for better test reliability and clarity.
FakeClassName implementations that provide controllable, inspectable behaviorensureAllEventsConsumed() validation method when using Turbinessrc/test/java/com/stripe/android/.../FakeClassName.ktFake + interface/class name (e.g., FakeEventReporter, FakeCustomerRepository)internal to scope to the test moduleAlways use default parameters to make instantiation easy:
internal class FakeCustomerRepository(
private val paymentMethods: List<PaymentMethod> = emptyList(),
private val customer: Customer? = null
) : CustomerRepository {
// Implementation
}
For complex setup, provide a companion object factory method:
internal class FakePaymentMethodVerticalLayoutInteractor(
initialState: PaymentMethodVerticalLayoutInteractor.State,
initialShowsWalletsHeader: Boolean = false,
private val viewActionRecorder: ViewActionRecorder<PaymentMethodVerticalLayoutInteractor.ViewAction>
) : PaymentMethodVerticalLayoutInteractor {
companion object {
fun create(
paymentMethodMetadata: PaymentMethodMetadata = PaymentMethodMetadataFactory.create(),
initialShowsWalletsHeader: Boolean = true,
viewActionRecorder: ViewActionRecorder<PaymentMethodVerticalLayoutInteractor.ViewAction> = ViewActionRecorder()
): FakePaymentMethodVerticalLayoutInteractor {
// Complex initialization logic
val initialState = /* construct complex state */
return FakePaymentMethodVerticalLayoutInteractor(
initialState = initialState,
initialShowsWalletsHeader = initialShowsWalletsHeader,
viewActionRecorder = viewActionRecorder
)
}
}
}
Directly expose Turbines for test verification:
internal class FakeEventReporter : EventReporter {
val paymentFailureCalls = Turbine<PaymentFailureCall>()
val paymentSuccessCalls = Turbine<PaymentSuccessCall>()
override fun onPaymentFailure(error: Throwable, source: PaymentEventSource) {
paymentFailureCalls.add(PaymentFailureCall(error, source))
}
override fun onPaymentSuccess(paymentMethod: PaymentMethod) {
paymentSuccessCalls.add(PaymentSuccessCall(paymentMethod))
}
}
Define data classes to capture method call parameters:
data class PaymentFailureCall(val error: Throwable, val source: PaymentEventSource)
data class PaymentSuccessCall(val paymentMethod: PaymentMethod)
data class DetachRequest(val paymentMethodId: String, val customerId: String)
Implement a validation method that ensures all turbine events were consumed:
fun ensureAllEventsConsumed() {
paymentFailureCalls.ensureAllEventsConsumed()
paymentSuccessCalls.ensureAllEventsConsumed()
detachRequests.ensureAllEventsConsumed()
updateRequests.ensureAllEventsConsumed()
// ... validate all turbines
}
Tests should call this method after verification:
@Test
fun `test payment flow`() = runTest {
val fake = FakeEventReporter()
// Perform operations
fake.onPaymentSuccess(paymentMethod)
// Verify calls
assertThat(fake.paymentSuccessCalls.awaitItem()).isEqualTo(
PaymentSuccessCall(paymentMethod)
)
// Validate all events consumed
fake.ensureAllEventsConsumed()
}
For classes that handle view actions, use ViewActionRecorder:
internal class FakePaymentMethodVerticalLayoutInteractor(
initialState: PaymentMethodVerticalLayoutInteractor.State,
private val viewActionRecorder: ViewActionRecorder<PaymentMethodVerticalLayoutInteractor.ViewAction>
) : PaymentMethodVerticalLayoutInteractor {
override fun handleViewAction(viewAction: PaymentMethodVerticalLayoutInteractor.ViewAction) {
viewActionRecorder.record(viewAction)
// Optional: implement state changes based on action
}
}
Include ViewActionRecorder in factory with default:
companion object {
fun create(
paymentMethodMetadata: PaymentMethodMetadata = PaymentMethodMetadataFactory.create(),
viewActionRecorder: ViewActionRecorder<PaymentMethodVerticalLayoutInteractor.ViewAction> = ViewActionRecorder()
): FakePaymentMethodVerticalLayoutInteractor {
return FakePaymentMethodVerticalLayoutInteractor(
initialState = /* ... */,
viewActionRecorder = viewActionRecorder
)
}
}
Reference these fakes from the codebase as gold standards:
paymentsheet/src/test/java/com/stripe/android/paymentsheet/analytics/FakeEventReporter.kt
validate() method checking all turbinespaymentsheet/src/test/java/com/stripe/android/utils/FakeCustomerRepository.kt
paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/FakePaymentMethodVerticalLayoutInteractor.kt
ensureAllEventsConsumed() that calls it on all Turbinescreate() factory methodUse 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