mcpbeat

Create Fake

stripe/create-fake

Use when creating a fake test implementation in stripe-android — covers FakeClassName pattern, Turbine call tracking, ViewActionRecorder, and ensureAllEventsConsumed validation

2k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
1532
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/stripe/stripe-android --skill create-fake

The instruction itself

15 sections, as written by the author

Creating Fakes for Testing

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.

Core Principles

  • Prefer fakes over mocks - Create FakeClassName implementations that provide controllable, inspectable behavior
  • Use Turbine for call tracking - Track method invocations with Turbine channels for verification
  • Provide default parameters - Make fakes easy to instantiate with sensible defaults
  • Enable validation - Implement ensureAllEventsConsumed() validation method when using Turbines

Basic Fake Structure

File Naming and Location

  • Place fakes in the test source directory: src/test/java/com/stripe/android/.../FakeClassName.kt
  • Name pattern: Fake + interface/class name (e.g., FakeEventReporter, FakeCustomerRepository)
  • Mark as internal to scope to the test module

Constructor Pattern

Always 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
            )
        }
    }
}

Tracking Method Calls with Turbine

Basic Turbine Pattern

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))
    }
}

Data Classes for Call Capture

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)

Validation with ensureAllEventsConsumed

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()
}

ViewActionRecorder Pattern

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
        )
    }
}

Excellent Real-World Examples

Reference these fakes from the codebase as gold standards:

FakeEventReporter

paymentsheet/src/test/java/com/stripe/android/paymentsheet/analytics/FakeEventReporter.kt

  • 16 different Turbine channels for comprehensive event tracking
  • Clean validate() method checking all turbines
  • Data classes for each event type
  • Gold standard for Turbine usage

FakeCustomerRepository

paymentsheet/src/test/java/com/stripe/android/utils/FakeCustomerRepository.kt

  • Excellent use of default parameters
  • Multiple Turbines for tracking different operations (detach, update, setDefault)
  • Data classes for request tracking

FakePaymentMethodVerticalLayoutInteractor

paymentsheet/src/test/java/com/stripe/android/paymentsheet/verticalmode/FakePaymentMethodVerticalLayoutInteractor.kt

  • ViewActionRecorder integration
  • Companion object factory method with sophisticated defaults

Quick Reference

  • Need to track method calls? → Use Turbine with data classes
  • Tracking view actions? → Use ViewActionRecorder
  • Need to verify all events consumed? → Implement ensureAllEventsConsumed() that calls it on all Turbines
  • Complex initialization? → Add companion object create() factory method
  • Always → Provide default parameters for easy instantiation

How to use it

Copy the folder

Take stripe/create-fake from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.