iwmh’s blog

ただの書き散らし/メモ

OkHttpClientのresponse.body?.string()が、try{}で囲まれると失敗する

  • 失敗するコード
class WebApiClientImpl @Inject constructor(
    private val injectableConstants: InjectableConstants,
    private val authStateManager: AuthStateManager,
    private val okHttpClient: OkHttpClient,
    private val gson: Gson
) : WebApiClient {

    // Get User's Saved Shows
    override suspend fun getUsersSavedShows(): PagingObject<ItemShow> {

        val url = injectableConstants.baseUrl + "/me/shows";

        // Make a request to API endpoint.
        val request = Request.Builder()
            .url(url)
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer ${authStateManager.authState.accessToken}")
            .build()

        return withContext(Dispatchers.IO) {

            try {
                val response = okHttpClient.newCall(request).execute()
                if (!response.isSuccessful) {
                    throw Exception(response.toString())
                }

                val tokenType = object : TypeToken<PagingObject<ItemShow>>() {}.type
                var respString = response.body?.string()

                gson.fromJson(
                    respString,
                    tokenType
                )
            } catch (e: Exception){
                throw e
            }
        }
    }

}
  • テストコード
@SmallTest
class InstrumentedUnitTest{

    companion object {
        lateinit var localKeyValueStorageImpl: LocalKeyValueStorageImpl
        lateinit var remoteDataSourceImpl: RemoteDataSourceImpl
        lateinit var mainRepository: MainRepository

        lateinit var mockWebServer: MockWebServer

        @BeforeClass
        @JvmStatic
        fun init() {
            // Context of the app under test.
            val context = InstrumentationRegistry.getInstrumentation().targetContext

            val mainKey = MasterKey.Builder(context)
                .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
                .build()

            // Backup the initial AuthState value.
            val prefs = EncryptedSharedPreferences.create(
                context,
                Constants.shared_prefs_file,
                mainKey,
                EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
            )

            // Init for storage, remotedatasource and repository.
            val okHttpClient = OkHttpClient()
            localKeyValueStorageImpl = LocalKeyValueStorageImpl(prefs)
            val authStateManager = AuthStateManager(localKeyValueStorageImpl)
            authStateManager.authService = AuthorizationService(context)
            val gson = Gson()
            val injectableConstants = InjectableConstants(
                baseUrl = "http://localhost:8080"
            )
            val webApiClientImpl = WebApiClientImpl(injectableConstants ,authStateManager, okHttpClient, gson)

            remoteDataSourceImpl = RemoteDataSourceImpl(webApiClientImpl, LocalKeyValueStorageImpl(prefs))

            mainRepository = MainRepositoryImpl(remoteDataSourceImpl)

            // mock web server

            mockWebServer = MockWebServer()
            mockWebServer.start(8080)
        }

        @AfterClass
        @JvmStatic
        fun end(){
            mockWebServer.shutdown()
        }

    }

    @Test
    fun get_following_shows() = runBlocking{

        val successResponseData = """
            {
              // JSONデータ。中身省略
              "total": 15
            }
        """

        val successResponse = MockResponse().apply {
            setResponseCode(200)
            setHeader("Content-Type", "application/json")
            setBody(successResponseData)
        }

        mockWebServer.enqueue(successResponse)

        val result = mainRepository.getUsersSavedShows()

        assertEquals(15, result.items.count())
    }
}
  • エラーメッセージ

cannot be cast to java.lang.Void

  • 修正後コード(抜粋)
    // Get User's Saved Shows
    override suspend fun getUsersSavedShows(): PagingObject<ItemShow> {

        val url = injectableConstants.baseUrl + "/me/shows";

        // Make a request to API endpoint.
        val request = Request.Builder()
            .url(url)
            .header("Content-Type", "application/json")
            .header("Authorization", "Bearer ${authStateManager.authState.accessToken}")
            .build()

        return withContext(Dispatchers.IO) {

            val response = okHttpClient.newCall(request).execute()
            if (!response.isSuccessful) {
                throw Exception(response.toString())
            }

            val tokenType = object : TypeToken<PagingObject<ItemShow>>() {}.type
            var respString = response.body?.string()

            gson.fromJson(
                respString,
                tokenType
            )
        }
    }