如何通过espresso UI测试初始化​​Presenter的可为空变量以避免NPE [英] How to initialize nullable variable of presenter through espresso UI test to avoid NPE

查看:65
本文介绍了如何通过espresso UI测试初始化​​Presenter的可为空变量以避免NPE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为使用Kotlin构建的android应用编写Espresso UI测试.我编写了一个基本的UI测试,以测试loginFragment中存在的UI元素.

I am trying to write Espresso UI test for an android app build with kotlin. I have written a basic UI test to test the UI elements present in the loginFragment.

@LargeTest
class LoginFragmentTest {

    private val serverUrl = "https://example.com"

    @JvmField
    var activityRule = ActivityTestRule(AuthenticationActivity::class.java, true, true)

    @Rule
    fun rule() = activityRule

    @Before
    fun setUp() {
        rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) {
            newInstance(serverUrl)
        }      
    }


    @Test
    fun check_UI_elements(){
        onView(withId(R.id.text_login)).check(matches(withText("Login")))
        onView(withId(R.id.text_username_or_email)).check(matches(withHint("Username or email")))
        onView(withId(R.id.text_password)).check(matches(withHint("Password")))
        onView(withId(R.id.button_log_in)).check(matches(withText("Login")))
        onView(withId(R.id.button_forgot_your_password)).check(matches(withText("Forgot your password?")))
    }

登录片段

class LoginFragment : Fragment(), LoginView {
    @Inject
    lateinit var presenter: LoginPresenter
    @Inject
    lateinit var analyticsManager: AnalyticsManager
    private var serverName: String? = null
    private val editTextsDisposable = CompositeDisposable()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        AndroidSupportInjection.inject(this)

        arguments?.run {
            serverName = getString(SERVER_NAME)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = container?.inflate(R.layout.fragment_authentication_log_in)

.....
}

登录演示者

class LoginPresenter @Inject constructor(
    private val view: LoginView,
    private val strategy: CancelStrategy,
    private val navigator: AuthenticationNavigator,
    private val tokenRepository: TokenRepository,
    private val localRepository: LocalRepository,
    private val settingsInteractor: GetSettingsInteractor,
    private val analyticsManager: AnalyticsManager,
    private val saveCurrentServer: SaveCurrentServerInteractor,
    private val saveAccountInteractor: SaveAccountInteractor,
    private val factory: RocketChatClientFactory,
    val serverInteractor: GetConnectingServerInteractor
) {
    // TODO - we should validate the current server when opening the app, and have a nonnull get()
    private var currentServer = serverInteractor.get()!!
    private val token = tokenRepository.get(currentServer)
    private lateinit var client: RocketChatClient
    private lateinit var settings: PublicSettings

    fun setupView() {
        setupConnectionInfo(currentServer)
        setupForgotPasswordView()
    }

...
}

我还有SaveConnectingServerInteractor和GetConnectingServerInteractor,它们用于在身份验证时存储服务器URL.

I also have SaveConnectingServerInteractor and GetConnectingServerInteractor which is used to store the server url at the time of authentication.

open class SaveConnectingServerInteractor @Inject constructor(
        @ForAuthentication private val repository: CurrentServerRepository
    ) {
        fun save(url: String) = repository.save(url)
    }
open class GetConnectingServerInteractor @Inject constructor(
    @ForAuthentication private val repository: CurrentServerRepository
) {
    fun get(): String? = repository.get()

    fun clear() {
        repository.clear()
    }
}

LoginFragmentModule

LoginFragmentModule

@Module
class LoginFragmentModule {

    @Provides
    @PerFragment
    fun loginView(frag: LoginFragment): LoginView = frag

    @Provides
    @PerFragment
    fun provideLifecycleOwner(frag: LoginFragment): LifecycleOwner = frag
}

LoginFragmentProvider

LoginFragmentProvider

@Module abstract class LoginFragmentProvider {

    @ContributesAndroidInjector(modules = [LoginFragmentModule::class])
    @PerFragment
    abstract fun provideLoginFragment(): LoginFragment
}

但是在运行测试时,由于变量currentServer变为null,因为其中没有保存url,因此我得到了KotlinNullPointerException.有什么办法可以避免在运行UI测试期间使其为null.我已经尝试过使用Elvis运算符并修改LoginPresenter,但我想知道还有其他可行的方法.我只想使用任何URL字符串初始化当前服务器的值,以避免在运行测试期间出现NPE.

But on running the test I am getting KotlinNullPointerException as the variable currentServer is becoming null because there is no url saved in it. Is there any way I can avoid it from being null during running UI test. I have tried using elvis operator and modify LoginPresenter but I want to know is there anything other way which can work. I just want to initialize the value of current server with any URL string to avoid NPE during running tests.

我也尝试使用

@Before
fun setUp() {
    `when`(serverInteractor.get()).thenReturn("http://fakeurl")`
    rule().activity.addFragmentBackStack(ScreenViewEvent.Login.screenName, R.id.fragment_container) {
        newInstance(serverUrl)
    }      
}

但随后它会抛出

java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String chat.rocket.android.server.domain.CurrentServerRepository.get()' on a null object reference
at chat.rocket.android.server.domain.GetConnectingServerInteractor.get(GetConnectingServerInteractor.kt:9)
at chat.rocket.android.authentication.login.ui.LoginFragmentTest.setUp(LoginFragmentTest.kt:42)

推荐答案

我认为您应该将演示者的模拟版本注入片段中以进行测试. 您可以遵循以下步骤: https://proandroiddev.com/writing-espresso-instrumentation-带有Dagger2-kotlin-d30f12c4769b的测试 或只是文档: https://square.github.io/dagger/#using (模块替代)

I believe that you should inject mocked version of presenter into the fragment for test purposes. You could follow this: https://proandroiddev.com/writing-espresso-instrumentation-tests-with-dagger2-kotlin-d30f12c4769b or just documentation: https://square.github.io/dagger/#using (Module Overrides)

这篇关于如何通过espresso UI测试初始化​​Presenter的可为空变量以避免NPE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆