architecture-components-samples icon indicating copy to clipboard operation
architecture-components-samples copied to clipboard

userRepository Coroutine test faile

Open makazemi opened this issue 5 years ago • 0 comments

I see an issue in the "GithubBrowserSample" sample -> move-to-new-coroutines-artifact branch-> UserRepositoryTest under test folder. I write same test for my repository using this way.But my test didn't pass. The error say actual and excepted not Identical while in the it show same content. my project in github safeApiCall method:

suspend fun <T> safeApiCall(
    isNetworkAvailable: Boolean,
    coroutineContext: CoroutineContext=Dispatchers.IO,
    apiCall: suspend () -> GenericApiResponse<T>

): GenericApiResponse<T> {
    if (!isNetworkAvailable) {
        return ApiErrorResponse(ErrorBody(message = UNABLE_TODO_OPERATION_WO_INTERNET))
    }
    return withContext(coroutineContext) {
        try {
            withTimeout(NETWORK_TIMEOUT) {
                apiCall.invoke()
            }
        } catch (throwable: Throwable) {
            throwable.printStackTrace()
            when (throwable) {
                is TimeoutCancellationException -> {
                    val code = "408" // timeout error code
                    ApiErrorResponse<T>(ErrorBody(code, ERROR_CHECK_NETWORK_CONNECTION))
                }
                is IOException -> {
                    ApiErrorResponse<T>(ErrorBody(message = NETWORK_ERROR))
                }
                is HttpException -> {
                    val code = throwable.code().toString()
                    val errorResponse =
                        ErrorBody.convertToObject(convertErrorBody(throwable)).userMessage
                    ApiErrorResponse<T>(ErrorBody(code, errorResponse))
                }
                else -> {
                    ApiErrorResponse<T>(ErrorBody(message = ERROR_UNKNOWN))

                }
            }
        }
    }
}

this is fakeApiservice:

open class FakeGithubService(
     var getPostImpl: suspend (token: String) -> GenericApiResponse<PostResponse> = notImplemented1()
) :ApiService {
    companion object {
        private fun <T, R> notImplemented1(): suspend (t: T) -> R {
            return { t: T ->
                TODO("")
            }
        }

        private fun <T, R> notImplemented2(): suspend (t: T) -> R {
            return { t: T ->
                TODO("")
            }
        }
    }
    override suspend fun getPosts(token: String): GenericApiResponse<PostResponse> = getPostImpl(token)
}

This is my Test class:

@ExperimentalCoroutinesApi
@RunWith(RobolectricTestRunner::class)
class MainRepositoryTest :CoroutineTestBase() {
    private lateinit var repository: MainRepository
    private  var apiService =FakeGithubService()
    private lateinit var postDao: PostDao


    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    @Before
    fun init() {
        val db = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext<Application>(), AppDatabase::class.java)
            .allowMainThreadQueries()
            .build()
        postDao=db.getPostDao()
        repository=MainRepositoryImpl(apiService,postDao)
    }

    @Test
    fun getPostApiOnlyTest() {
        /** GIVEN  **/
        val postResponse= TestUtil.createPostResponse()

        /** WHEN **/
        val calledService = CompletableDeferred<Unit>()
        runBlocking {
            apiService.getPostImpl ={
                calledService.complete(Unit)
                GenericApiResponse.create(Response.success(postResponse))
            }

           repository.getPostsApiOnly(this.coroutineContext).addObserver().apply {
                calledService.await()
                advanceUntilIdle()

               /** THEN **/
                assertItems(
                   DataState.loading(true),
                    DataState.data(postResponse.posts)
                )
            }

        }

    }
    
}

This is my repository:

@Singleton
class MainRepositoryImpl @Inject constructor(private val apiService: ApiService
,private val postDao: PostDao):MainRepository {
    override fun getPostsApiOnly(coroutineContext: CoroutineContext): LiveData<DataState<List<Post>>> =
        liveData {
            emit(DataState.loading(true))
            val apiResult = safeApiCall(true,coroutineContext) {
               apiService.getPosts()
            }

            emit(
                object : ApiResponseHandler<List<Post>,PostResponse>(
                    response = apiResult
                ) {
                    override suspend fun handleSuccess(resultObj: PostResponse): DataState<List<Post>> {
                        return DataState.data(resultObj.posts)
                    }


                }.getResult()
            )
        }

}

this is ApiResponseHandler class:

abstract class ApiResponseHandler<ResultType, Data>(
    private val response: GenericApiResponse<Data>
) {

    private val TAG: String = "AppDebug"

    suspend fun getResult(): DataState<ResultType> {

        return when (response) {
            is ApiSuccessResponse -> {
                handleSuccess(resultObj = response.body)
            }
            is ApiErrorResponse -> {

                buildError(
                    response.error.message ?: ErrorHandling.ERROR_UNKNOWN,
                    response.error.code.toString()
                )

            }
            is ApiEmptyResponse -> {
                buildError(
                    code = "204",
                    message = "HTTP 204. Returned NOTHING."
                )
            }
        }
    }

    abstract suspend fun handleSuccess(resultObj: Data): DataState<ResultType>

}

makazemi avatar Jun 27 '20 10:06 makazemi