{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars/sdk_sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["code-group"]},"type":"markdown"},"seo":{"title":"Unit testing the quickstart flow","description":"The specifications of Ratepay's APIs for easy payment transactions.","siteUrl":"https://docs.ratepay.com","keywords":"Ratepay developer portal, Ratepay api portal, Ratepay api reference docs","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"unit-testing-the-quickstart-flow","__idx":0},"children":["Unit testing the quickstart flow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This is a complete test of the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/developer/sdk/getting-started/quickstart"},"children":["quickstart"]},"'s authorize → capture flow: it"," ","mocks ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["RatepayClient"]},", stubs an ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Accepted"]}," outcome for both calls, and asserts the code under test reacts"," ","correctly, with no network access, so no sandbox credentials required."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The examples use JUnit 5 plus Mockito (Java) or MockK (Kotlin), neither ships with the SDK. Add them as"," ","test dependencies."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Assume the code under test is a small method that wraps the quickstart flow:"]},{"$$mdtype":"Tag","name":"CodeGroup","attributes":{"mode":"tabs"},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"java","data-title":"Java — code under test","header":{"title":"Java — code under test","controls":{"copy":{}}},"source":"public class CheckoutService {\n    private final RatepayClient client;\n\n    public CheckoutService(RatepayClient client) {\n        this.client = client;\n    }\n\n    public String authorizeAndCapture(AuthorizationRequest request, CaptureRequest captureRequest) {\n        AuthorizeOutcome outcome = client.authorize(request, null);\n        if (outcome.kind() != AuthorizeOutcome.Kind.ACCEPTED) {\n            throw new IllegalStateException(\"Authorization not accepted: \" + outcome.kind());\n        }\n\n        CaptureOutcome captureOutcome = client.capture(outcome.ratepayTransactionId(), captureRequest, null);\n        if (captureOutcome.kind() != CaptureOutcome.Kind.ACCEPTED) {\n            throw new IllegalStateException(\"Capture not accepted: \" + captureOutcome.kind());\n        }\n\n        return ((CaptureOutcome.Accepted) captureOutcome).getRatepayCaptureId();\n    }\n}\n","lang":"java"},"children":[]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","data-title":"Kotlin — code under test","header":{"title":"Kotlin — code under test","controls":{"copy":{}}},"source":"class CheckoutService(private val client: RatepayClient) {\n    fun authorizeAndCapture(request: AuthorizationRequest, captureRequest: CaptureRequest): String {\n        val outcome = client.authorize(request)\n        check(outcome is AuthorizeOutcome.Accepted) { \"Authorization not accepted: ${outcome.kind()}\" }\n\n        val captureOutcome = client.capture(outcome.ratepayTransactionId(), captureRequest)\n        check(captureOutcome is CaptureOutcome.Accepted) { \"Capture not accepted: ${captureOutcome.kind()}\" }\n\n        return captureOutcome.ratepayCaptureId\n    }\n}\n","lang":"kotlin"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"the-test","__idx":1},"children":["The test"]},{"$$mdtype":"Tag","name":"CodeGroup","attributes":{"mode":"tabs"},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"java","data-title":"Java (JUnit 5 + Mockito)","header":{"title":"Java (JUnit 5 + Mockito)","controls":{"copy":{}}},"source":"import com.ratepay.sdk.AuthorizeOutcome;\nimport com.ratepay.sdk.CaptureOutcome;\nimport com.ratepay.sdk.RatepayClient;\nimport com.ratepay.sdk.model.api.payment.*;\nimport com.ratepay.sdk.model.extension.ResponseLinks;\nimport org.junit.jupiter.api.Test;\nimport java.math.BigDecimal;\nimport java.time.OffsetDateTime;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass CheckoutServiceTest {\n\n    @Test\n    void authorizesThenCapturesOnAcceptance() {\n        RatepayClient client = mock(RatepayClient.class);\n        AuthorizeOutcome.Accepted authorizeAccepted = new AuthorizeOutcome.Accepted(\n            \"txn_123\", null, OffsetDateTime.now(), null, new ResponseLinks(null), null\n        );\n        when(client.authorize(any(), any())).thenReturn(authorizeAccepted);\n        CaptureOutcome.Accepted captureAccepted = new CaptureOutcome.Accepted(\n            \"cap_456\", OffsetDateTime.now(), new ResponseLinks(null)\n        );\n        when(client.capture(eq(\"txn_123\"), any(), any())).thenReturn(captureAccepted);\n        CheckoutService service = new CheckoutService(client);\n\n        String captureId = service.authorizeAndCapture(minimalAuthorizationRequest(), minimalCaptureRequest());\n\n        assertEquals(\"cap_456\", captureId);\n    }\n\n    private static AuthorizationRequest minimalAuthorizationRequest() {\n        return new AuthorizationRequest(\n            new Buyer(\n                new Address(\"Berlin\", \"DE\", \"Torstraße\", \"10119\", null, \"1\"),\n                new Contact(\"jane.doe@example.com\", \"+49 30 1234567\"),\n                null, null,\n                new Person(java.time.LocalDate.of(1990, 4, 12), \"Jane\", \"Doe\", null),\n                null\n            ),\n            \"EUR\",\n            new PaymentMethod(PaymentOption.OPEN_INVOICE, TransferType.BANK_TRANSFER),\n            java.util.List.of(new ShopBasket(\n                new BigDecimal(\"29.99\"),\n                java.util.List.of(new Item(\n                    new BigDecimal(\"29.99\"), \"Wireless Mouse\", BigDecimal.ONE, new BigDecimal(\"19\"),\n                    \"SKU-1001\", null, null, null, null, null, null, null, null\n                )),\n                \"SHOP-001\",\n                null, null, null, null\n            )),\n            null, null, null, null, null, null, null, null, null\n        );\n    }\n\n    private static CaptureRequest minimalCaptureRequest() {\n        return new CaptureRequest(new BigDecimal(\"29.99\"), null, null, null, null, null, null, null, null);\n    }\n}\n","lang":"java"},"children":[]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","data-title":"Kotlin (JUnit 5 + MockK)","header":{"title":"Kotlin (JUnit 5 + MockK)","controls":{"copy":{}}},"source":"import com.ratepay.sdk.AuthorizeOutcome\nimport com.ratepay.sdk.CaptureOutcome\nimport com.ratepay.sdk.RatepayClient\nimport com.ratepay.sdk.model.api.payment.*\nimport io.mockk.every\nimport io.mockk.mockk\nimport org.junit.jupiter.api.Assertions.assertEquals\nimport org.junit.jupiter.api.Test\nimport java.math.BigDecimal\nimport java.time.LocalDate\n\nclass CheckoutServiceTest {\n\n    @Test\n    fun `authorizes then captures on acceptance`() {\n        val client = mockk<RatepayClient>()\n        val authorizeAccepted = mockk<AuthorizeOutcome.Accepted> {\n            every { ratepayTransactionId() } returns \"txn_123\"\n        }\n        every { client.authorize(any(), idempotencyKey = isNull()) } returns authorizeAccepted // named arg: authorize has a second overload taking an attestation token\n\n        val captureAccepted = mockk<CaptureOutcome.Accepted> {\n            every { ratepayCaptureId } returns \"cap_456\"\n        }\n        every { client.capture(\"txn_123\", any(), any()) } returns captureAccepted\n        val service = CheckoutService(client)\n\n        val captureId = service.authorizeAndCapture(minimalAuthorizationRequest(), minimalCaptureRequest())\n\n        assertEquals(\"cap_456\", captureId)\n    }\n\n    private fun minimalAuthorizationRequest() = AuthorizationRequest(\n        paymentMethod = PaymentMethod(PaymentOption.OPEN_INVOICE, TransferType.BANK_TRANSFER),\n        currency = \"EUR\",\n        buyer = Buyer(\n            billingAddress = Address(street = \"Torstraße\", streetNumber = \"1\", zipCode = \"10119\", city = \"Berlin\", countryCode = \"DE\"),\n            contact = Contact(email = \"jane.doe@example.com\", phone = \"+49 30 1234567\"),\n            person = Person(firstName = \"Jane\", lastName = \"Doe\", dateOfBirth = LocalDate.of(1990, 4, 12)),\n        ),\n        shopBaskets = listOf(ShopBasket(\n            partnerShopId = \"SHOP-001\",\n            grossAmount = BigDecimal(\"29.99\"),\n            items = listOf(Item(\n                grossUnitPrice = BigDecimal(\"29.99\"),\n                name = \"Wireless Mouse\",\n                taxRate = BigDecimal(\"19\"),\n                quantity = BigDecimal.ONE,\n                articleNumber = \"SKU-1001\",\n            )),\n            vats = null,\n        )),\n    )\n\n    private fun minimalCaptureRequest() = CaptureRequest(grossAmount = BigDecimal(\"29.99\"))\n}\n","lang":"kotlin"},"children":[]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Two mocking details worth noticing:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The Java test constructs real ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AuthorizeOutcome.Accepted"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CaptureOutcome.Accepted"]}," instances with"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["new"]},". The Kotlin test instead mocks the outcome types themselves with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mockk<...> { every { ... } }"]}," and"," ","stubs only the properties ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CheckoutService"]}," actually reads."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["AuthorizeOutcome.ratepayTransactionId()"]}," is a method, not a property, hence"," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["every { ratepayTransactionId() } returns \"txn_123\""]}," in MockK, not ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["every { outcome.ratepayTransactionId }"]},"."]}]}]},"headings":[{"value":"Unit testing the quickstart flow","id":"unit-testing-the-quickstart-flow","depth":1},{"value":"The test","id":"the-test","depth":2}],"frontmatter":{"seo":{"title":"Unit testing the quickstart flow"}},"lastModified":"2026-11-03T16:42:42.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/developer/sdk/testing/unit-testing-the-quickstart-flow","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}