Android,Room 在使用 Robolectric 进行单元测试时失败

标签 android unit-testing kotlin android-room robolectric

我正在尝试为 View 模型创建一些测试。

View 模型包括一个调用数据库的数据库实例化
CallRoomDatabase db = CallRoomDatabase.getDatabase(application);
其中 getDatabase 采用 Dao() 的一个实例

  @Database(entities = {CallEntity.class}, version = 1)
 public abstract class CallRoomDatabase extends RoomDatabase {

public abstract CDao cDao();

// marking the instance as volatile to ensure atomic access to the variable
private static volatile CRoomDatabase INSTANCE;

public static CRoomDatabase getDatabase(final Context context) {
    if (INSTANCE == null) {
        synchronized (CallRoomDatabase.class) {
            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                        CRoomDatabase.class, "database")
                        // Wipes and rebuilds instead of migrating if no Migration object.
                        // Migration is not part of this codelab.
                        .fallbackToDestructiveMigration()
                        .addCallback(sRoomDatabaseCallback)
                        .build();
            }
        }
    }
    return INSTANCE;
}

但是,当尝试在测试中实例化模型时,.build() 上出现错误。以上
  java.lang.NullPointerException
at androidx.room.Room.getGeneratedImplementation(Room.java:79)
at androidx.room.RoomDatabase$Builder.build(RoomDatabase.java:952)
at com.s.o.dbutils.CRoomDatabase.getDatabase(CRoomDatabase.java:32)
at com.s.o.viewmodels.CViewModelTest.checkForNuTest(CViewModelTest.kt:66)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.powermock.modules.junit4.rule.PowerMockStatement$1.run(PowerMockRule.java:83)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)

RoomDatabase.java
            T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);

Room.java klassnull
        static <T, C> T getGeneratedImplementation(Class<C> klass, String suffix) {

我试过在测试中根本不使用模型,只需实例化数据库
          val db = CRoomDatabase.getDatabase(ApplicationProvider.getApplicationContext())

还是一样断.build()
任何想法如何克服该异常?

我们实际上不需要以某种方式测试数据库,只需要该模型中包含的一些功能,所以一些避免错误的方法就足够了。

最佳答案

房间应该被测试为 Android Instrumentation Test ,而不是 JUnit 测试。

更新:

使用mockito模拟数据库和任何存储库。

使用 mockito 方法,例如:

  • @Mock - 模拟注释以模拟全局和局部变量。
  • mock - 在线启动类的模拟。
  • when - 为模拟配置返回行为。
  • verify - 在模拟及其方法上断言交互。
  • times - 与 verify 一起使用来断言对模拟及其方法的调用次数。
  • any - 一个参数匹配器,用于向模拟断言提供的值。

  • 使用 Mockito,例如。我不知道你的代码是如何工作的,我做了一些假设,比如 Call.class 的存在以及你需要什么模拟:
    @Mock private CallRoomDatabase database;
    @Mock private CRoomDatabase cRoomDatabase;
    @Mock private CDao cDao;
    
    private MyClass myClass;
    
    @Before 
    public void setUp() {
        // initiate all globally defined mocks annotated with @Mock
        initMocks(this);
    
        // Setup our expected behaviour from the mock
        when(database.getDatabase()).thenReturn(cRoomDatabase);
        myClass = new myClass(database, cDao);
    }
    
    @Test 
    public void givenSomeTest_whenCallingGetCall_thenInsertNewCall() {
        // Setup our expected behaviour from the mock
        when(cDao.getCall()).thenReturn(mock(Call.class));
    
        // do test
    
        // assert mock interaction with arguments and number of expected calls
        verify(cDao, times(1)).insertCall(any(mock(Call.class)))
    }
    

    关于Android,Room 在使用 Robolectric 进行单元测试时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60720976/

    相关文章:

    spring-boot - Spring Boot + Kotlin注释错误

    android - Android 中的谷歌地图 API

    Android Studio - 删除模块 - IncorrectOperationException : Must not change document outside command or undo-transparent action

    包含自己的单元测试的 Python 脚本

    arrays - 如何使用流过滤 2D IntArray 并将其映射到 Set 中

    java - 如何在 Kotlin 编写的接口(interface)中使用默认方法的 Java 8 功能

    android - 将sqlite转换为加密数据库 :

    android - 如何自定义 float ActionBar的背景?

    python - 使用unittest django测试存储在内存中的csv文件

    unit-testing - xcodebuild headless (headless)运行测试?