简体   繁体   English

如何在单元测试中获取上下文以在内存数据库对象中创建 Room 数据库

[英]How to get Context in unit test to create Room database in memory database object

I'm trying to test this one function in my application repository class which performs a database insertion.我正在尝试在执行数据库插入的应用程序存储库类中测试这个函数。 I'm using Koin as my dependency injection library.我使用Koin作为我的依赖注入库。 To do the testing I need to create a Database version that gets built in memory.为了进行测试,我需要创建一个内置于内存的数据库版本。 To create that database I need the Android application context.要创建该数据库,我需要 Android 应用程序上下文。 So I created my test class like below.所以我创建了我的测试类,如下所示。

import android.content.Context
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
import com.chathuranga.shan.mycontacts.di.applicationModule
import com.chathuranga.shan.mycontacts.di.repositoryModule
import com.chathuranga.shan.mycontacts.room.AppDatabase
import org.junit.After
import org.junit.Test

import org.junit.Before
import org.junit.Rule
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.loadKoinModules
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.dsl.module
import org.koin.test.KoinTest
import org.koin.test.inject
import org.mockito.MockitoAnnotations

class ContactRepositoryTest : KoinTest {

    private val contactRepository: ContactRepository by inject()
    private lateinit var appDatabase: AppDatabase

    @get:Rule
    val rule = InstantTaskExecutorRule()

    @Before
    fun setUp() {

        startKoin {
            printLogger()
            modules(listOf(applicationModule,repositoryModule))
        }

        MockitoAnnotations.initMocks(this)

        val context = ApplicationProvider.getApplicationContext<Context>()
        //val instrumentationContext = InstrumentationRegistry.getInstrumentation().targetContext

        appDatabase = Room
            .inMemoryDatabaseBuilder(context, AppDatabase::class.java)
            .allowMainThreadQueries()
            .build()

        loadKoinModules(module { single(override = true) { appDatabase } })
    }

    @Test
    fun insertContact() {

        val firstName = "Chathuranga"
        val secondName = "Shan"
        val phone = "07711247890"

        contactRepository.insertContact(firstName,secondName,phone,null,null)

    }

    @After
    fun tearDown() {
        stopKoin()
    }
}

And I'm getting this exception.我得到了这个例外。

java.lang.IllegalStateException: No instrumentation registered! java.lang.IllegalStateException:未注册检测! Must run under registering instrumentation.必须在注册检测下运行。

As you can see I tried two ways to get Context (check the commented line in above class) and both failed the same way.如您所见,我尝试了两种获取Context (检查上面类中的注释行),但都以相同的方式失败。 And error pointed to the place where I create Context object.错误指向了我创建Context对象的地方。 This test class in test folder not in androidTest folder. test文件夹中的这个测试类不在androidTest文件夹中。 I want to separate this function and other functions that gonna come in the future and test in this class.我想把这个函数和其他将来会出现的函数分开,并在这个类中测试。

Here are my dependencies这是我的依赖项

//Testing
testImplementation 'junit:junit:4.12'
testImplementation "org.mockito:mockito-core:2.21.0"
testImplementation 'android.arch.core:core-testing:1.1.1'
testImplementation 'androidx.test:core:1.2.0'
testImplementation 'org.koin:koin-test:2.0.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

My dependency injection class.我的依赖注入类。

val applicationModule = module {
    single { AppDatabase.getDatabaseInstance(androidContext().applicationContext) }
}

val activityModule = module {

    scope(named<MainActivity>()) {
        scoped { (activity: MainActivity) ->
            Navigation
                .findNavController(activity, R.id.hostFragment)
        }
    }
}

I'm new to testing.我是测试新手。 If the way I have grasped the concept of unit testing please point it out.如果我已经掌握了单元测试的概念,请指出。 Otherwise Point out the problem with this code.否则指出此代码的问题。 Thanks.谢谢。

Create Context with Robolectric in a local unit test在本地单元测试中使用 Robolectric 创建上下文

For local unit tests run on the JVM, Robolectric works.对于在 JVM 上运行的本地单元测试,Robolectric 有效。 If this is in an instrumented test, then Robolectric is not needed.如果这是在仪器测试中,则不需要 Robolectric。 InstrumentationRegistry can be used as in Joe Birch's sample . InstrumentationRegistry可以在Joe Birch 的示例中使用

1. Add libraries 1. 添加库

JUnit 5 JUnit 5

build.gradle构建.gradle

testImplementation "org.robolectric:robolectric:X.X.X"
testImplementation "androidx.test.ext:junit:X.X.X"

Junit 4结界 4

Built-in use with JUnit 4 and AndroidX library.内置使用 JUnit 4 和 AndroidX 库。

2. Create app Context with ApplicationProvider 2. 使用ApplicationProvider创建应用上下文

Junit 5结界 5

See: Build local unit tests > Include framework dependencies - Android documentation请参阅:构建本地单元测试 > 包含框架依赖项- Android 文档

SomeTest.kt SomeTest.kt

import androidx.test.core.app.ApplicationProvider

@RunWith(RobolectricTestRunner::class)
class SomeTest {

    @Test
    fun someTest() {
        val appContext = ApplicationProvider.getApplicationContext<Context>()
        ...
    }

}


JUnit 4 JUnit 4

See: Robolectric's documentation请参阅:Robolectric 的文档

3. Handle SDK 29/Java 9 error with class annotation @Config 3.使用类注解@Config处理SDK 29/Java 9错误

See: How to add Java 9 to Android Studio?请参阅:如何将 Java 9 添加到 Android Studio? - StackOverflow - 堆栈溢出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM