Тестирование с сетью. Разные ответы

В статье Простой тест для работы с сетью мы узнали как сделать самый простой веб сервер для тестирования. В этой статье мы его немного расширим и сделаем более гибким для разных запросов.

Сначала мы добавим в наш Api еще один вызов

interface ApiTest {  
    @GET("characters")  
    fun loadCharacters(): Call<List<CharacterResponse>>  
  
    @GET("episodes")  
    fun loadEpisodes(): Call<List<EpisodeResponse>>  
}
data class EpisodeResponse(  
    @SerializedName("name") val name: String,  
    @SerializedName("date") val date: Date  
)

Добавим теории

В теории практически любой запрос в сеть возвращает какой-то ответ. Не будем рассматривать специфические случаи и представим, что в идеале нам будет возвращаться какой-то json. Можно эти ответы хранить в виде переменных в файле с имплементацией MockWebServer, но это не совсем правильно. Лучше их хранить в виде json файлов, которые будут доступны только для тестов.

Расширим создание вебсервера:

internal fun createMockServer(listener: DispatchListener): MockWebServer {  
    val mockWebServer = MockWebServer()  
    mockWebServer.start(8080)  
    mockWebServer.dispatcher = object : Dispatcher() {  
        override fun dispatch(request: RecordedRequest): MockResponse {  
            val responseFile = buildString {  
                append(listener.convertUrlToLocalFile(request.path.orEmpty(), method = request.method))  
                append(".json")  
            }  
            val content = getMockResponse(responseFile)  
            return MockResponse().setResponseCode(200).setBody(content)  
        }  
    }  
  
    return mockWebServer  
}

fun interface DispatchListener {  
    fun convertUrlToLocalFile(path: String, method: String?): String?  
}

Пара функций для чтения контента из файла

fun getFileAsString(filePath: String): String {  
    return Thread.currentThread().contextClassLoader?.getResourceAsStream(filePath)?.bufferedReader().use { it?.readText() }.orEmpty()  
}  
  
fun getMockResponse(fileName: String) = getFileAsString(fileName)

Определимся, что файлы с ответами сервера у нас лежат в директории moduleName/src/test/resources где по умолчанию moduleName=app

Последнее, что осталось сделать - указать нашему вебсерверу как обрабатывать запросы и содержимое какого файла возвращать.

@Before  
fun setup() {  
    mockWebServer = createMockServer { path, method ->  
        when (path) {  
            "/characters" -> "response_characters"  
            "/episodes" -> "response_episodes"  
            else -> null  
        }  
    }  
  
    api = createApi<ApiTest>(mockWebServer)  
}

В следующем посте мы будем работать с Api не напрямую, а через репозиторий