首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

ViewModel单元测试

ViewModel 是 Android Jetpack 库中的一个组件,它的主要目的是以生命周期感知的方式存储和管理 UI 相关的数据。ViewModel 的设计使得数据可以在配置更改(如屏幕旋转)时保持不变,并且它的生命周期比 Activity 或 Fragment 更长。

基础概念

  • 生命周期感知:ViewModel 不会因为 Activity 或 Fragment 的销毁而销毁,它会在配置更改后继续存在。
  • 数据持久性:ViewModel 可以用来保存临时数据,这些数据在 Activity 或 Fragment 重建时仍然可用。
  • 解耦:ViewModel 有助于将 UI 控制逻辑从 Activity 或 Fragment 中分离出来,使得代码更加清晰和易于维护。

优势

  1. 避免数据丢失:在屏幕旋转等配置更改时,ViewModel 中的数据不会丢失。
  2. 简化代码:将业务逻辑从 Activity 或 Fragment 中移出,使得 UI 组件更加专注于显示和交互。
  3. 易于测试:ViewModel 类通常不依赖于 Android 框架,因此可以更容易地进行单元测试。

类型

  • 基本 ViewModel:直接继承自 ViewModel 类。
  • LiveData:可以与 ViewModel 结合使用,以实现数据的观察者模式。
  • SavedStateHandle:用于保存和恢复 ViewModel 中的数据。

应用场景

  • 表单数据保持:用户在填写表单时,即使屏幕旋转,数据也不会丢失。
  • 复杂计算或数据处理:将耗时的操作放在 ViewModel 中,避免阻塞 UI 线程。
  • 网络请求结果管理:ViewModel 可以持有网络请求的结果,并在数据更新时通知 UI。

单元测试

单元测试 ViewModel 主要是为了确保其逻辑的正确性。以下是进行 ViewModel 单元测试的一些步骤和示例代码:

准备工作

首先,确保你的项目中已经添加了必要的测试依赖,例如 JUnit 和 Mockito。

代码语言:txt
复制
dependencies {
    testImplementation 'junit:junit:4.13.2'
    testImplementation 'org.mockito:mockito-core:3.12.4'
}

示例 ViewModel

假设我们有一个简单的 ViewModel,它负责处理用户登录逻辑。

代码语言:txt
复制
public class LoginViewModel extends ViewModel {
    private MutableLiveData<Boolean> loginResult = new MutableLiveData<>();

    public LiveData<Boolean> getLoginResult() {
        return loginResult;
    }

    public void login(String username, String password) {
        // 模拟登录逻辑
        boolean success = "admin".equals(username) && "password".equals(password);
        loginResult.postValue(success);
    }
}

单元测试代码

使用 JUnit 和 Mockito 来编写单元测试。

代码语言:txt
复制
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
import androidx.lifecycle.Observer;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class LoginViewModelTest {

    @Rule
    public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();

    private LoginViewModel viewModel;

    @Mock
    private Observer<Boolean> observer;

    @Before
    public void setUp() {
        viewModel = new LoginViewModel();
        viewModel.getLoginResult().observeForever(observer);
    }

    @Test
    public void testLoginSuccess() {
        viewModel.login("admin", "password");
        verify(observer).onChanged(true);
    }

    @Test
    public void testLoginFailure() {
        viewModel.login("wrongUser", "wrongPass");
        verify(observer).onChanged(false);
    }
}

遇到问题及解决方法

如果在单元测试中遇到问题,比如 ViewModel 中的数据没有按预期更新,可能的原因包括:

  • 线程问题:LiveData 的更新可能不在主线程上执行。
  • 观察者未注册:确保在测试开始前已经注册了观察者。
  • 逻辑错误:ViewModel 中的业务逻辑可能存在 bug。

解决方法:

  • 使用 InstantTaskExecutorRule 确保 LiveData 的更新在主线程上执行。
  • 确保在测试开始前注册了观察者,并在测试结束后注销。
  • 仔细检查 ViewModel 中的业务逻辑,确保其正确性。

通过以上步骤和方法,可以有效地对 ViewModel 进行单元测试,确保其功能的正确性和稳定性。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

  • Jetpack:ViewModel

    1.引入背景 引入ViewModel之前,存在如下几个问题: (1)有的时候一个Activity里面嵌套了多个fragment,但是这些fragment里面用的是同一个数据,为了同步这些数据,我们需要用接口来传参...(2)屏幕旋转,会销毁重建,如果数据类型比较简单,同时数据量也不大,可以通过onSaveInstanceState()存储数据.但如果是大量数据,不方便序列化及反序列化,则上述方法将不适用. 2.ViewModel...的使用 (1)gradle中引入 implementation 'android.arch.lifecycle:extensions:1.1.1' (2)新建ViewModel实体类 public class...UserModel extends ViewModel { String name; int age; } (3)获取ViewModel UserModel model = ViewModelProviders.of...点进去看就知道是HashMap 4.总结 ViewModel说白了就是内部生成一个fragment来管理生命周期,同时用HashMap保存数据,相对简单.它和LiveData以及Lifecycle组合使用会更好

    69320

    Android Jetpack - ViewModel

    ViewModel 简述 ViewModel 旨在以生命周期感知的形式存储和管理 UI 控制器(Activity/Fragment 等)相关的数据,可以解决 UI 控制器中数据无法正确保留以及数据在其复杂的生命周期中难以维护的痛点...ViewModel ?...我用一个非常简单的 Demo 来展示它的基础用法,通常我们为 app 集成 ViewModel 遵循如下几个步骤: 1、创建一个继承 ViewModel 的类来分离出 UI 控制器中的数据 2、建立 ViewModel...和 UI 控制器之间的通信 3、在 UI 控制器中使用 ViewModel 1、创建 ViewModel 创建 MainActivityViewModel 并继承 ViewModel class MainActivityViewModel...= _startTime } 2、关联 UI 控制器和 ViewModel UI 控制器必须知道自己和哪个 ViewModel 进行关联,这样它才能知道去哪里取回数据,注意,不要在 ViewModel

    87520

    Jetpack系列——ViewModel

    ViewModel独立于组件的配置的变化,也就是说,当发生特殊情况导致Activity重新执行某些生命周期时,ViewModel的生命周期并不会发生变化。...为了证明Activity在执行各生命周期时,ViewModel并不会随之变化,所以我们可以在ViewModel中使用Handler或者RxJava做一个定时循环任务,观测Activity是否会影响ViewModel...> mMap = new HashMap(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel...但如果ViewModel中必须要用到Context怎么办呢,可以将ViewModel类继承自AndroidViewModel,AndroidViewModel继承自ViewModel,并且接收Applcation...ViewModel不会受Actvity生命周期的影响,那是不是可以使用ViewModel替代onSaveInstanceState()方法呢?

    64110

    Andorid-JetPack-ViewModel组件

    其实就是ViewModel实例被保存了下来,页面重建之后获取的ViewModel是同一个 2.基本用法 常规用法:存储的数据,仅仅只能当页面因为配置变更导致的销毁再重建时可复用,复用的是ViewModel...复用实现原理 准确点来说,应该是ViewModel如何做到在宿主销毁了,还能继续存在.以至于页面恢复重建后,还能接着复用 肯定是前后获取到的是同一个ViewModel实例对象 我们先来看下获取ViewModel...> mMap = new HashMap(); final void put(String key, ViewModel viewModel) { ViewModel oldViewModel...ViewModel viewModel = mViewModelStore.get(key); //2.判断viewModel该实例是不是我们传入的modelClass...(T) viewModel; } } 当调用get()方法的时候,我们只是传递了一个ViewModel的.class对象,就会把我们ViewModel的className名字拼接上DEFAULT_KEY

    1.8K30

    【Jetpack】ViewModel 架构组件 ( 视图 View 和 数据模型 Model | ViewModel 作用 | ViewModel 生命周期 | 代码示例 | 使用注意事项 )

    文章目录 一、Activity 遇到的问题 二、视图 View 和 数据模型 Model 三、ViewModel 架构组件作用 四、ViewModel 代码示例 1、ViewModel 视图模型 2...: 在 Activity 的 首次启动时 创建 ViewModel 实例对象 , 如果 Activity 多次启动 , ViewModel 只会创建一次 ; 绑定 : Activity 与 ViewModel...关联时 , 开始绑定 ViewModel , Activity 组件中 绑定 ViewModel 代码如下 ; // 获取 ViewModel myViewModel...会与 UI 组件解绑 ; 销毁 : ViewModel 关联的所有的 Activity 或 Fragment 全部销毁 , 则 ViewModel 实例对象 也会被销毁 ; 六、ViewModel 使用注意事项...---- ViewModel 使用注意事项 : 使用 ViewModel 时 , 不要将 Context 上下文对象传入 ViewModel 中 , 否则会导致内存泄漏 ; 如果要使用 Context

    87120

    Jetpack--LifeCycle、ViewModel、LiveData

    Jetpack中,官方提供了ViewModel组件,我们应该继承它实现我们的ViewModel层业务 1.瞬态数据保存 例如以前我们手机屏幕旋转时,如果没有配置,那么Activity会重新创建,数据就会丢失...使用ViewModel,我们可以什么都不做就解决这个问题 现在来创建一个Activity,点击按钮让一个数字不断加一,布局文件如下: viewmodel; import androidx.lifecycle.ViewModel; /** * Created by aruba on 2021/...通过反射获取ViewModel,并实现点击方法 package com.aruba.viewmodel; import androidx.appcompat.app.AppCompatActivity...进度值的观察,注意这边获取ViewModel时Owner要用Activity的上下文,因为实现联动需要使用同一个ViewModel,不同Owner会生成不同的实例 package com.aruba.livedata2

    1.7K20

    扫码

    添加站长 进交流群

    领取专属 10元无门槛券

    手把手带您无忧上云

    扫码加入开发者社群

    相关资讯

    热门标签

    活动推荐

      运营活动

      活动名称
      广告关闭
      领券