简体   繁体   English

Kotlin 协程单元测试错误:线程“main @coroutine#1 @coroutine#2”中的异常 java.lang.NullPointerException

[英]Kotlin Coroutine Unit Testing Error: Exception in thread "main @coroutine#1 @coroutine#2" java.lang.NullPointerException

I'm trying to unit test a presenter that I made with Kotlin coroutines, and this is also my first time using Mockito我正在尝试对使用 Kotlin 协程制作的演示者进行单元测试,这也是我第一次使用 Mockito

Whenever I try to run the unit test I'm getting the following error the first time it tries to do anything with my view while in the coroutine每当我尝试运行单元测试时,它第一次尝试在协程中对我的视图执行任何操作时都会收到以下错误

Exception in thread "main @coroutine#1 @coroutine#2" java.lang.NullPointerException
    at .signin.SignInPresenter$subscribe$1.doResume(SignInPresenter.kt:45)
    at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54)
    at kotlinx.coroutines.experimental.DispatchedKt.resumeCancellable(Dispatched.kt:208)
    at kotlinx.coroutines.experimental.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:35)
    at kotlinx.coroutines.experimental.CoroutineStart.invoke(CoroutineStart.kt:111)
    at kotlinx.coroutines.experimental.AbstractCoroutine.start(AbstractCoroutine.kt:161)
    at kotlinx.coroutines.experimental.BuildersKt.launch(Builders.kt:68)
    at kotlinx.coroutines.experimental.BuildersKt.launch$default(Builders.kt:61)
    at .signin.SignInPresenter.subscribe(SignInPresenter.kt:42)

This is the relevant part of my presenter, the line referenced in the error is view.showSigninPanel这是我的演示者的相关部分,错误中引用的行是view.showSigninPanel

class SignInPresenter(
    private val view: SignInContract.View,
    private val userRepo: ParseAuthController,
    private val contextPool: CoroutineContextProvider
) : SignInContract.Presenter {

    private val coroutineJobs: MutableList<Job> = mutableListOf()

    override fun subscribe() {
        view.loadBackgroundImage()
        view.setUpSignInPanel()
        view.setUpKeyboardListener()

        coroutineJobs.add(launch(contextPool.Main) {
            if (!userRepo.isAuthenticated()) {
                view.showSignInPanel()
                subscribeToLoginValidation()
                subscribeToPaswordEmailValidation()
            } else {
                view.launchMainActivity()
            }
        })
    }

The call to userRepo.isAuthenticated() is a suspended calluserRepo.isAuthenticated()的调用是暂停调用

I'm passing in a test coroutine context into my presenter as per this article根据本文,我正在将测试协程上下文传递给我的演示者

https://android.jlelse.eu/mastering-coroutines-android-unit-tests-8bc0d082bf15 https://android.jlelse.eu/mastering-coroutines-android-unit-tests-8bc0d082bf15

class TestContextProvider : CoroutineContextProvider() {
    override val Main: CoroutineContext = Unconfined
    override val IO: CoroutineContext = Unconfined
}

This is my unit test currently这是我目前的单元测试

class SignInPresenterTest {

    private lateinit var view: SignInContract.View
    private lateinit var presenter: SignInPresenter
    private lateinit var parseAuthController: ParseAuthController

    @Before
    fun setUp() {
        view = mock(SignInContract.View::class.java)

        parseAuthController = mock(ParseAuthController::class.java)

        presenter = SignInPresenter(
            view,
            parseAuthController,
            TestContextProvider()
        )
    }

    @After
    fun tearDown() {
        presenter.dispose()
    }

    @Test
    fun subscribeNotAuthenticatedShowSignInPanel() {
        runBlocking {
            val expectedResult = false
            `when`(parseAuthController.isAuthenticated()).thenReturn(expectedResult)

            presenter.subscribe()
        }

        verify(view).showSignInPanel()
    }
}

UPDATE: I've been doing some additional tests, and it looks like if I remove the suspend call within my presenter if (!userRepo.isAuthenticated()) it won't crash and I can verify if something has run with Mockito, but this isn't an actual solution... but something with that suspending call is causing problems?更新:我一直在做一些额外的测试,看起来如果我在演示者中删除暂停调用if (!userRepo.isAuthenticated())它不会崩溃,我可以验证 Mockito 是否运行了某些东西,但是这不是一个实际的解决方案......但是那个暂停呼叫的东西会导致问题吗?

Problem solved!问题解决了!

The above code is actually correct.上面的代码实际上是正确的。 I had the wrong Mockito dependency.我有错误的 Mockito 依赖。

I was copying some dependencies from a co-workers repo and they were using this library that provides some Kotlin specific functionality我正在从同事 repo 复制一些依赖项,他们正在使用这个库,它提供了一些 Kotlin 特定的功能

https://github.com/nhaarman/mockito-kotlin https://github.com/nhaarman/mockito-kotlin

Either there's something in there breaking support for coroutines, or maybe there's some different requirements to make it work?要么有一些东西破坏了对协同程序的支持,要么可能有一些不同的要求才能让它工作?

Updating to the latest Mockito dependency works.更新到最新的 Mockito 依赖项工作。

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

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