访问 mObservables 时,单元测试 RecyclerView 适配器抛出 NullPointerException

Cru*_*ces 8 android unit-testing android-recyclerview

我的视图模型包含一个非常简单的 recyclerview 适配器

当我尝试向它发送消息(依次调用notifyDatasetChanged)时,它会抛出这样的异常

java.lang.NullPointerException
at androidx.recyclerview.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:11996)
at
Run Code Online (Sandbox Code Playgroud)

问题是mObservers变量 fromAdapterDataObservable为空

问题是这扩展了Observable<AdapterDataObserver>它反过来定义mObservers

protected final ArrayList<T> mObservers = new ArrayList<T>();
Run Code Online (Sandbox Code Playgroud)

所以基本上我的适配器被实例化的那一刻,它会调用

private final AdapterDataObservable mObservable = new AdapterDataObservable();
Run Code Online (Sandbox Code Playgroud)

(顺便调用,mObservable 不为空)

反过来应该调用 mObservers = new ArrayList<T>();

有人可以解释为什么从不调用它吗?或者是否有办法解决这个问题?

作为旁注,适配器不是模拟的,它是一个实体对象。

编辑:

这是我正在使用的测试代码:

class LoginViewModelTest {

     private lateinit var vm: LoginViewModel

        @get:Rule
        val rule = InstantTaskExecutorRule()

        @Before
        fun setUp() {

            whenever(settings.hasShownWelcome).thenReturn(false)
            whenever(settings.serverIp).thenReturn("http://127.0.0.1")

            //this is where the crash happens
            vm = LoginViewModel(settings, service, app, TestLog, TestDispatchers) { p -> permissionGranted }
        }
Run Code Online (Sandbox Code Playgroud)

下面是经过测试的代码:

class LoginViewModel(private val settings: ISettings, private val service: AppService, application: Application, l: ILog, dispatchers: IDispatchers, val permissionChecker: (String) -> Boolean) :  BaseViewModel(application, l, dispatchers)

    val stepAdapter :StepAdapter

    init {
        val maxSteps = calculateSteps()
        //after this assignment, during the normal run, the stepAdapter.mObservable.mObservers is an empty array
        //during unit tests, after this assignment it is null
        stepAdapter = StepAdapter(maxSteps) 
    }
Run Code Online (Sandbox Code Playgroud)

or_*_*vir 1

我不知道您是否已经找到解决方案,但这适用于像我这样遇到类似问题的其他人:

使测试成为android 测试(又名仪表测试)而不是单元测试。

虽然我无法完全解释原因,但似乎当通知适配器有关更改(notifyItemChanged()notifyDataSetChanged())时,有关 android 内部逻辑的某些内容需要实际的RecyclerView/adapter 来接收消息。

一旦我将测试从Test文件夹移动到AndroidTest文件夹,问题就解决了。

聚苯乙烯

确保删除旧的构建配置!android studio 一直引用旧的(在Test文件夹中),如果你不删除它,你会收到一个classNotFound错误