Skip to content

Test DataSource

Ali Sadeghi edited this page Jan 27, 2026 · 6 revisions

Test DataSource Agent

Generates DataSource tests using Ktor MockEngine.

Spawned by: test-orchestrator during /feature-test command

What It Tests

  • HTTP success cases (200 OK with valid responses)
  • HTTP error codes (400, 401, 404, 500, 503)
  • Network failures (connection refused, timeout)
  • JSON parsing edge cases (malformed, missing fields, extra fields)
  • Request verification (URL, method, headers, body)

Example Output

class LoginRemoteDataSourceTest {
    private lateinit var mockEngine: MockEngine

    private fun createDataSource(
        handler: suspend MockRequestHandleScope.(HttpRequestData) -> HttpResponseData
    ): LoginRemoteDataSource {
        mockEngine = MockEngine { request -> handler(request) }
        val client = HttpClient(mockEngine) {
            install(ContentNegotiation) { json(Json { ignoreUnknownKeys = true }) }
            install(Resources)
        }
        return LoginRemoteDataSourceImpl(ApiClient(client))
    }

    @Test
    fun `login returns success when API returns 200`() = runTest {
        val dataSource = createDataSource { request ->
            respond(
                content = LoginFixtures.validLoginResponseJson,
                status = HttpStatusCode.OK,
                headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString())
            )
        }

        val result = dataSource.login(LoginFixtures.createLoginRequest())
        assertTrue(result is Either.Success)
    }

    @Test
    fun `login returns failure on 401 Unauthorized`() = runTest {
        val dataSource = createDataSource { request ->
            respond(
                content = LoginFixtures.error401Json, // {"detail": "...", "code": null}
                status = HttpStatusCode.Unauthorized,
                headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString())
            )
        }

        val result = dataSource.login(LoginFixtures.createLoginRequest())

        // HTTP 401 always maps to ErrorConst.Unauthorized
        assertTrue(result is Either.Failure)
        val error = (result as Either.Failure).error as ErrorModel.MessageCode
        assertEquals("You must login", error.message)
        assertEquals(1001, error.code)
    }

    @Test
    fun `login returns failure on connection error`() = runTest {
        val dataSource = createDataSource { _ ->
            throw Exception("Connection refused")
        }

        val result = dataSource.login(LoginFixtures.createLoginRequest())

        assertTrue(result is Either.Failure)
        assertEquals(ErrorConst.NoNetwork, (result as Either.Failure).error)
    }
}

Error Handling Pattern

All tests follow the ErrorConst pattern:

  • HTTP 401 always maps to ErrorConst.Unauthorized (message: "You must login (#1001)")
  • Blank/null detail in response triggers ServerUnknownError(httpCode)
  • Connection failures trigger ErrorConst.NoNetwork

Back to Testing Agents | Agents

Clone this wiki locally