我有一个 ViewModel 与用例对话并返回一个流,即Flow<MyResult>
. 我想对我的 ViewModel 进行单元测试。我是使用流程的新手。需要帮助请。这是下面的视图模型 -
class MyViewModel(private val handle: SavedStateHandle, private val useCase: MyUseCase) : ViewModel() {
private val viewState = MyViewState()
fun onOptionsSelected() =
useCase.getListOfChocolates(MyAction.GetChocolateList).map {
when (it) {
is MyResult.Loading -> viewState.copy(loading = true)
is MyResult.ChocolateList -> viewState.copy(loading = false, data = it.choclateList)
is MyResult.Error -> viewState.copy(loading = false, error = "Error")
}
}.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext)
Run Code Online (Sandbox Code Playgroud)
MyViewState 看起来像这样 -
data class MyViewState(
val loading: Boolean = false,
val data: List<ChocolateModel> = emptyList(),
val error: …
Run Code Online (Sandbox Code Playgroud) 我的用例与存储库通信并发出多个数据,如下所示 -
class MyUseCase(private val myRepoInterface: MyRepoInterface) : MyUseCaseInterface {
override fun performAction(action: MyAction) = flow {
emit(MyResult.Loading)
emit(myRepoInterface.getData(action))
}
}
Run Code Online (Sandbox Code Playgroud)
相同的单元测试如下所示 -
class MyUseCaseTest {
@get:Rule
val instantExecutorRule = InstantTaskExecutorRule()
@Mock
private lateinit var myRepoInterface: MyRepoInterface
private lateinit var myUseCaseInterface: MyUseCaseInterface
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
myUseCaseInterface = MyUseCase(myRepoInterface)
}
@After
fun tearDown() {
}
@Test
fun test_myUseCase_returnDataSuccess() {
runBlocking {
`when`(myRepoInterface.getData(MyAction.GetData))
.thenReturn(MyResult.Data("data"))
// Test
val flow = myUseCaseInterface.performAction(MyAction.GetData)
flow.collect { data ->
Assert.assertEquals(data, MyResult.Loading)
Assert.assertEquals(data, MyResult.Data("data"))
}
} …
Run Code Online (Sandbox Code Playgroud) 我有一个导航 xml,其功能如下 -
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/navigation_featureB.xml"
app:startDestination="@id/FragmentB">
<fragment
android:id="@+id/FragmentB"
android:name="FragmentB"
android:label="FragmentB">
<deepLink app:uri="App://FragmentB" />
</fragment>
</navigation>
Run Code Online (Sandbox Code Playgroud)
在我的FeatureA
片段中,我执行以下操作 -
val uri = Uri.parse("App://FragmentB")
findNavController().navigate(uri)
Run Code Online (Sandbox Code Playgroud)
我知道如何使用safeArgs
没有深层链接。如何将数据传递到具有深层链接的其他功能?
我正在使用 WorkManager 如下 -
class LocationWorker(
ctx: Context, params: WorkerParameters
) : CoroutineWorker(ctx, params), KoinComponent {
private val locationDataRepository: LocationDataRepository by inject()
override suspend fun doWork(): Result {
return try {
locationDataRepository.triggerLocationUpdates()
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}
Run Code Online (Sandbox Code Playgroud)
我将 Worker 触发为 -
val myWorker =
PeriodicWorkRequestBuilder<LocationWorker>(
15,
TimeUnit.MINUTES
).addTag(
"location"
).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"location",
ExistingPeriodicWorkPolicy.KEEP,
myWorker
)
Run Code Online (Sandbox Code Playgroud)
如您所见,WorkManager 的最短时间为 15 分钟。我想在很短的时间间隔内跟踪位置,比如每隔几秒钟,我也希望即使在手机屏幕关闭时也能跟踪位置。WorkManager 是满足我要求的正确选择还是您会建议我一些其他 API?
我正在对我的视图模型进行单元测试,并且我总是不断地获得NullPointerException
.
这是我的视图模型代码 -
class LoginViewModel(private val myUseCase: MyUseCase) :BaseViewModel() {
private val viewState = LoginViewState()
fun onLoginClicked() =
Transformations.map(
myUseCase.performUseCaseAction(
MyAction.LoginUser(
email,password)
)
) {
when (it) {
is MyResult.Loading -> viewState.copy(loading = true)
is MyResult.UserLoggedIn -> viewState.copy(
loading = false,
userLoggedIn = true
)
is MyResult.Error -> viewState.copy(loading = false, error = it.error)
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是 MyUseCase 接口代码 -
interface MyUseCase {
fun performUseCaseAction(action: MyAction): LiveData<MyResult>
}
Run Code Online (Sandbox Code Playgroud)
这是相同的单元测试 -
@RunWith(MockitoJUnitRunner::class)
class LoginViewModelTest {
@get:Rule
val instantExecutorRule …
Run Code Online (Sandbox Code Playgroud) 我有一个带有按钮的视图 -
我的查看代码 -
private val viewModel: MyViewModel by viewModel()
override fun onCreateView(...): View? {
//Button click
view.getMyData.setOnClickListener {
viewModel.onGetDataClicked.observe(this, Observer {
view?.progressBar?.isVisible = it.loading
view?.description?.text = it.data.value
})
}
return view
}
Run Code Online (Sandbox Code Playgroud)
我的视图模型代码 -
val viewState = MyViewState()
val onGetDataClicked =
Transformations.map(myDomain.getData(MyAction.GetMyDataAction)) {
when (it) {
is MyResult.Loading -> viewState.copy(loading = true, error = null)
is MyResult.Success -> viewState.copy(
loading = false,
data = it.data,
error = null
)
is MyResult.Error -> viewState.copy(
loading = false,
error = it.error …
Run Code Online (Sandbox Code Playgroud) 我有一个像这样的 JSON 存储在执行我的 Github 操作的文件夹/路径中 -
{
"version":"1",
"sampleArray":[
{
"id":"1"
}
],
"secondArray":[
{
"secondId":"2"
}
]
}
Run Code Online (Sandbox Code Playgroud)
使用 Github 操作如何编辑值,id
例如:将id
值设置为“5”,sampleArray
以便我的 JSON 具有更新的值?
javascript continuous-integration json github github-actions
到目前为止,我一直在使用Flow
并将其映射到LiveData
如下所示 -
看起来MyService
像这样——
override fun provideData(action: MyAction) = flow {
emit(MyResult.Loading)
emit(dataRepository.getNewData())
}
Run Code Online (Sandbox Code Playgroud)
看起来ViewModel
像这样——
fun getData() = myService.provideData(MyAction.GetData).map {
}.asLiveData(Dispatchers.Default + viewModelScope.coroutineContext)
Run Code Online (Sandbox Code Playgroud)
我想搬到StateFlow
. 我怎样才能emit
像StateFlow
使用Flow
.
在我的片段中,
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.e(TAG, "Inside on view created")
lifecycleScope.launchWhenResumed {
Log.e(TAG, "Inside lifecyclescope get data")
viewModel.getData().collect {
// ....
}
}
}
override fun onResume() {
Log.e(TAG, "Inside on resume")
super.onResume()
}
Run Code Online (Sandbox Code Playgroud)
以下是不同场景下的日志序列 -
当应用程序刚刚打开时 -
视图内部已创建
简历里面
在生命周期范围内获取数据
当从一个片段回到这个片段时 -
视图内部已创建
简历里面
在生命周期范围内获取数据
现在问题来了...
当应用程序从后台进入前台时 -
简历里面
如您所见,我只看到onResume()
日志,但我也希望日志Inside lifecyclescope get data
出现。我在这里做错了什么吗?
android ×8
kotlin ×7
android-mvvm ×2
junit ×2
coroutine ×1
github ×1
javascript ×1
json ×1
junit4 ×1