🎭 Mockowanie

Mockowanie odpowiedzi do testów i developmentu.

Mock Interceptor

import rip.nerd.kitsunenet.mock.KNETMockInterceptor

val mockInterceptor = KNETMockInterceptor()
    .mock("GET", "/users") {
        KNETResponse(
            statusCode = 200,
            statusMessage = "OK",
            headers = mapOf("Content-Type" to "application/json"),
            bodyString = """[{"id": 1, "name": "Test User"}]"""
        )
    }
    .mock("POST", "/users") {
        KNETResponse(201, "Created", emptyMap(), """{"id": 2, "name": "New User"}""")
    }
    .mock("GET", "/users/\\d+") {  // Regex
        KNETResponse(200, "OK", emptyMap(), """{"id": 1, "name": "User"}""")
    }

val client = KNETClient.builder()
    .addInterceptor(mockInterceptor)
    .build()

// Teraz requesty są mockowane
val response = client.get("https://api.example.com/users")
// Zwraca mock response

Mock z plików JSON

// res/raw/mock_users.json
val mockInterceptor = KNETMockInterceptor()
    .mockFromResource("GET", "/users", R.raw.mock_users)
    .mockFromResource("GET", "/products", R.raw.mock_products)

// Lub z assets
val mockInterceptor = KNETMockInterceptor()
    .mockFromAsset("GET", "/users", "mocks/users.json")
    .mockFromAsset("GET", "/config", "mocks/config.json")

Dynamic mocks

val mockInterceptor = KNETMockInterceptor()
    .mockDynamic("POST", "/login") { request ->
        val body = request.data as? Map<*, *>
        val email = body?.get("email") as? String

        if (email == "test@example.com") {
            KNETResponse(200, "OK", emptyMap(),
                """{"token": "mock-token-123"}""")
        } else {
            KNETResponse(401, "Unauthorized", emptyMap(),
                """{"error": "Invalid credentials"}""")
        }
    }
    .mockDynamic("GET", "/users/(\\d+)") { request ->
        val userId = request.url.substringAfterLast("/")
        KNETResponse(200, "OK", emptyMap(),
            """{"id": $userId, "name": "User $userId"}""")
    }

Delay i błędy

val mockInterceptor = KNETMockInterceptor()
    // Symuluj opóźnienie
    .mock("GET", "/slow") {
        delay(2000)  // 2s delay
        KNETResponse(200, "OK", emptyMap(), """{"data": "slow"}""")
    }
    // Symuluj błąd sieci
    .mockError("GET", "/network-error") {
        throw IOException("Simulated network error")
    }
    // Symuluj timeout
    .mockError("GET", "/timeout") {
        throw SocketTimeoutException("Simulated timeout")
    }
    // Losowe błędy (chaos testing)
    .mockRandom("GET", "/flaky", errorRate = 0.3) {
        KNETResponse(200, "OK", emptyMap(), """{"data": "ok"}""")
    }

Response Mocker (Recording)

import rip.nerd.kitsunenet.mock.KNETResponseMocker

val mocker = KNETResponseMocker()

// Tryb nagrywania - zapisuje prawdziwe odpowiedzi
mocker.startRecording()
client.get("/users")  // Nagrywa response
client.get("/products")  // Nagrywa response
mocker.stopRecording()

// Zapisz do pliku
mocker.saveRecording(File("mocks.json"))

// ---

// Tryb playback - odtwarza nagrane
mocker.loadRecording(File("mocks.json"))
mocker.startPlayback()

// Teraz zwraca nagrane odpowiedzi
val response = client.get("/users")  // Z nagrania

W testach

class UserRepositoryTest {

    private val mockInterceptor = KNETMockInterceptor()
    private val client = KNETClient.builder()
        .addInterceptor(mockInterceptor)
        .build()
    private val repository = UserRepository(client)

    @Before
    fun setup() {
        mockInterceptor.clear()
    }

    @Test
    fun `should return users`() = runTest {
        // Given
        mockInterceptor.mock("GET", "/users") {
            KNETResponse(200, "OK", emptyMap(),
                """[{"id": 1, "name": "John"}]""")
        }

        // When
        val users = repository.getUsers()

        // Then
        assertEquals(1, users.size)
        assertEquals("John", users[0].name)
    }

    @Test
    fun `should handle error`() = runTest {
        // Given
        mockInterceptor.mock("GET", "/users") {
            KNETResponse(500, "Server Error", emptyMap(), "")
        }

        // When/Then
        assertThrows<ApiException> {
            repository.getUsers()
        }
    }
}

Feature flags

val mockInterceptor = if (BuildConfig.USE_MOCKS) {
    KNETMockInterceptor()
        .mockFromAsset("GET", "/users", "mocks/users.json")
        .mockFromAsset("GET", "/config", "mocks/config.json")
} else {
    null
}

val clientBuilder = KNETClient.builder()
if (mockInterceptor != null) {
    clientBuilder.addInterceptor(mockInterceptor)
}
val client = clientBuilder.build()

📚 Zobacz też