architecture-components-samples
architecture-components-samples copied to clipboard
userRepository Coroutine test faile
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>
}