问题描述
我想为我的repository
编写单元测试。 repository
的方法返回flow
。首先,addDiaryRate
方法的加载状态为emit
,然后从网络返回数据。我想验证addDiaryRate
方法是否先加载然后进行数据响应。我写了这个测试,但是我的测试失败了。错误提示期望值和实际值不相等。
java.lang.AssertionError: 预期:是
但是:是 预期:is 实际:
我使用Codelab和Google示例的示例代码。
这是MainRepository
:
class MainRepositoryImp constructor(
private val apiService: MainApiService,private val suggestionModelDao: SuggestionModelDao,private val userDao: UserDao,private val babyDao: BabyDao,private val diaryHotDao: DiaryHotDao,private val diaryUserDao: DiaryUserDao,private val hashTagModelDao: HashTagModelDao,private val diaryTopDao: DiaryTopDao,private val diaryResultSearchDao: DiaryResultSearchDao,private val rateModelDao: RateModelDao,private val medalDao: MedalDao,private val blogModelDao: BlogModelDao,private val seenDiaryDao: SeenDiaryDao,private val rateModelAppDao: RateModelAppDao,private val diarySavedDao: DiarySavedDao,private val diaryAnotherUserDao: DiaryAnotherUserDao,private val anotherUserInfoDao: AnotherUserInfoDao,private val followDao: FollowDao,private val suggestProductDao: SuggestProductDao,private val blogSuggestWithHashTagDao: BlogSuggestWithHashTagDao,private val suggestHashtagDao: SuggestHashtagDao,private val sessionManager: SessionManager
) : MainRepository {
override fun addratetoDiary(rate: String,diaryId: String): Flow<DataState<RateResponse>> =
flow {
emit(DataState.loading(true))
val apiResult = safeApiCall(
sessionManager.isConnectedToTheInternet()
) {
apiService.addrate(
diaryId,AddrateRequest(rate),sessionManager.cachedAccesstoken.value ?: ""
)
}
emit(
object : ApiResponseHandler<RateResponse,RateResponse>(
response = apiResult
) {
override suspend fun handleSuccess(resultObj: RateResponse): DataState<RateResponse> {
safeCacheCall {
diaryHotDao.updaterateStateDiary(
resultObj.data.symbolPath ?: "",diaryId,resultObj.data.rate
)
var countRate = 0
var userId = 0
userDao.fetchUser()?.let {
countRate = it.countRates + 1
userId = it.id
}
userDao.updateCountRate(countRate,userId)
}
return DataState.data(resultObj)
}
}.getResult()
)
}
}
这是我的考试班:
@ExperimentalCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@InternalCoroutinesApi
class MainRepositoryTest
{
private lateinit var repository: MainRepository
private var apiService = FakeUnitTestApiService()
private lateinit var suggestionModelDao: SuggestionModelDao
private lateinit var userDao: UserDao
private lateinit var babyDao: BabyDao
private lateinit var diaryHotDao: DiaryHotDao
private lateinit var diaryUserDao: DiaryUserDao
private lateinit var hashTagModelDao: HashTagModelDao
private lateinit var diaryTopDao: DiaryTopDao
private lateinit var diaryResultSearchDao: DiaryResultSearchDao
private lateinit var rateModelDao: RateModelDao
private lateinit var medalDao: MedalDao
private lateinit var blogModelDao: BlogModelDao
private lateinit var seenDiaryDao: SeenDiaryDao
private lateinit var rateModelAppDao: RateModelAppDao
private lateinit var diarySavedDao: DiarySavedDao
private lateinit var diaryAnotherUserDao: DiaryAnotherUserDao
private lateinit var anotherUserInfoDao: AnotherUserInfoDao
private lateinit var followDao: FollowDao
private lateinit var suggestProductDao: SuggestProductDao
private lateinit var blogSuggestWithHashTagDao: BlogSuggestWithHashTagDao
private lateinit var suggestHashtagDao: SuggestHashtagDao
private lateinit var sessionManager: SessionManager
private lateinit var db: AppDatabase
private lateinit var prefManager: PrefManager
@Rule
@JvmField
val instantExecutorRule = InstantTaskExecutorRule()
@ExperimentalCoroutinesApi
@get:Rule
var mainCoroutineRule = MainCoroutineRule()
@Before
fun init() {
val app = ApplicationProvider.getApplicationContext<Application>()
prefManager=PrefManager(app)
db = Room.inMemoryDatabaseBuilder(
app,AppDatabase::class.java
).allowMainThreadQueries().build()
initDao()
sessionManager = SessionManager(
app,userDao,babyDao,diaryHotDao,diaryTopDao,diaryUserDao,hashTagModelDao,medalDao,suggestionModelDao,diaryResultSearchDao,rateModelDao,blogModelDao,seenDiaryDao,rateModelAppDao,diarySavedDao,diaryAnotherUserDao,anotherUserInfoDao,followDao,suggestProductDao,blogSuggestWithHashTagDao,suggestHashtagDao,prefManager
)
repository = MainRepositoryImp(
apiService,sessionManager
)
}
private fun initDao() {
suggestionModelDao = db.getSuggestionModelDao()
userDao = db.getUserDao()
babyDao = db.getBabyDao()
diaryHotDao = db.getDiaryHotDao()
diaryUserDao = db.getDiaryUserDao()
hashTagModelDao = db.getHashTagModelDao()
diaryTopDao = db.getDiaryTopDao()
diaryResultSearchDao = db.getDiaryResultSearchDao()
rateModelDao = db.getRateModelDao()
medalDao = db.getMedalDao()
blogModelDao = db.getBlogModelDao()
seenDiaryDao = db.getSeenDiaryDao()
rateModelAppDao = db.getRateModelAppDao()
diarySavedDao = db.getDiarySavedDao()
diaryAnotherUserDao = db.getDiaryAnotherUserDao()
anotherUserInfoDao = db.getAnotherUserInfoDao()
followDao = db.getFollowDao()
suggestProductDao = db.getBlogProductDao()
blogSuggestWithHashTagDao = db.getBlogSuggestWithHashTagDao()
suggestHashtagDao = db.getBlogSuggestDao()
}
@Test
fun addratetest() = mainCoroutineRule.runBlockingTest{
/** GIVEN **/
val response = RateResponse(
RateModel(
id = "1",symbolPath = "symbol path",rate = 3,point = 2f,diaryId = "333",count = "34"
)
)
/** WHEN **/
repository.addratetoDiary("2","333").collect{
assertthat(it,`is`(DataState.loading<RateResponse>(true)))
assertthat(it,`is`(DataState.data<RateResponse>(response)))
}
}
解决方法
最后我找到了解决方案。
1-我使用runBlocking
而不是mainCoroutineRule.runBlockingTest
。
2-为了验证flow
的所有发射值,我们可以使用toList()
方法。
这是我的fakeApiService:
open class FakeUnitTestApiService(
var addRateImpl: suspend (
id: String,addRateRequest: AddRateRequest,token: String
) -> GenericApiResponse<RateResponse> = notImplemented2()
) : MainApiService {
companion object {
private fun <T,R> notImplemented1(): suspend (t: T) -> R {
return { t: T ->
TODO("")
}
}
private fun <T,R> notImplemented2(): suspend (t: T,s: T,l: T) -> R {
return { t: T,l: T ->
TODO("")
}
}
}
override suspend fun addRate(
id: String,token: String
): GenericApiResponse<RateResponse> = addRateImpl(id,addRateRequest,token)
}
这是我的测试功能:
@Test
fun addRateTest() = runBlocking{
/** GIVEN **/
val response = RateResponse(
RateModel(
id = "1",symbolPath = "symbol path",rate = 3,point = 2f,diaryId = "333",count = "34"
)
)
/** WHEN **/
apiService.addRateImpl = { s: String,s1: String ->
GenericApiResponse.create(Response.success(response))
}
val list=repository.addRateToDiary("2","333").toList()
/**THEN**/
assertThat(list.first().loading.isLoading,`is`(true))
assertThat(list.last().data?.peekContent(),`is`(response))
}