【问题标题】:Why "getSharedPreferences" return null in unit testing?为什么“getSharedPreferences”在单元测试中返回 null?
【发布时间】:2018-05-29 12:15:40
【问题描述】:

我的课程是用 Kotlin 编写的,这里是我的 SharedPreferenceHandler

   class SharedPreferenceHandler(sharedPrefs: SharedPreferences) {

        companion object {
            var mInstance: SharedPreferenceHandler = SharedPreferenceHandler(getPrefs())

            private fun getPrefs(): SharedPreferences {
                return Application.mInstance.getSharedPreferences(
                        "myApp", Context.MODE_PRIVATE)
            }

            fun getInstance(): SharedPreferenceHandler {
                return mInstance
            }
        }

        private var sharedPreferences = sharedPrefs

        var accessToken: String?
            get() = sharedPreferences.getString(SharedPreference.ACCESS_TOKEN.name, null)
            set(token) = sharedPreferences.edit().putString(SharedPreference.ACCESS_TOKEN.name, token).apply()
}

这是在presenter中调用的方法:

 override fun reload(vm: ViewModel) {
        super.updateViewModel(vm) {
           //some stuffs
        }
    }

这是我的测试方法:

@Test
public void reload() {
    when(SharedPreferenceHandler.Companion.getMInstance().getAccessToken()).thenReturn("234234234234234");

    presenter.reload(viewModel);
}

super.updateViewModel(vm) 的处理程序中,我调用“SharedPreferenceHandler.mInstance.accessToken!!)”

这就是抛出的内容:

引起:java.lang.IllegalStateException: Application.mInstanc…m", Context.MODE_PRIVATE) 不能为空 在 com.zuum.zuumapp.preferences.SharedPreferenceHandler$Companion.getPrefs(SharedPreferenceHandler.kt:18) 在 com.zuum.zuumapp.preferences.SharedPreferenceHandler$Companion.access$getPrefs(SharedPreferenceHandler.kt:14) 在 com.zuum.zuumapp.preferences.SharedPreferenceHandler.(SharedPreferenceHandler.kt:15)

我想通过调用“SharedPreferenceHandler.mInstance.accessToken!!”来获取accessToken!在我的测试课上。

可以在我的测试方法中得到它吗?

【问题讨论】:

  • 您是否使用 robolectric 进行测试?
  • 不,我使用 PowerMock 进行一些模拟

标签: unit-testing kotlin sharedpreferences


【解决方案1】:

您不能在单元测试中使用 Android SharedPreferences,但您可以通过以下方式模拟您的方法调用:

Mockito.`when`(SharedPreferenceHandler.mInstance.accessToken).thenReturn("token")

然后返回你需要的东西。

【讨论】:

    【解决方案2】:

    您不应该以这种方式测试您的代码。您应该为要模拟的类创建一个接口:

    interface MySharedPreferences {
        fun getAccessToken(): String
    }
    

    让你的 SharedPreferencesHandler 实现这个接口。然后在您的演示者(或您要测试的其他类)中将依赖项(例如通过构造函数或框架,如 Dagger/Kodein)注入到您的对象中。然后就有可能轻松地模拟这个界面。我假设在 @Before 你创建你测试的类 - 然后作为参数传递你模拟的 SharedPreferencesHandler。

    使用静态依赖项测试事物是可能的,但很棘手(很多人认为静态依赖项是反模式)。如何做到这一点在这里描述:How to android unit test and mock a static method

    例子:

     class MyPresenter(val sp: MySharedPreferences) {
         /* some code here */
         fun validateToken() {
             if (sp.getAccessToken() == "") throw new Exception()
         }
     }  
    

    就像你看到的sp 作为参数注入到这个类中。通常,您不会直接在代码中创建视图/演示者等,而是通过 DI 框架(如 Dagger 或 Kodein)。无论如何,静态依赖并不容易测试。可以模拟注入的接口依赖项,并且您不是在对象上操作,而是在行为上进行操作(因此它是更高级别的抽象)。所以,现在在你的测试中,你所要做的就是:

    class MyTest() {
    
        @Mock lateinit var sharedPreferencesMock: MySharedPreferences
        lateinit var instance: MyPresenter
    
        @Before
        fun setUp() {
            instance = MyPresenter(sharedPreferencesMock)
        }
    
        @Test
        fun testSomething() {
            `when`(sharedPreferencesMock.getAccessToken()).thenReturn("myAccessToken")
            /* here is your test body */
        }
    } 
    

    【讨论】:

    • 你能举个界面的例子吗?
    • 几乎没有添加解释的示例。
    • “MySharedPreferences”只是一个界面?
    • 是的。您注入的对象应该是接口的实例。你的类handler 应该实现这个接口——当你创建MyPresenter 你将传递实现这个接口的类的实例。
    猜你喜欢
    • 2019-10-03
    • 1970-01-01
    • 2021-12-27
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 2020-11-02
    • 2014-08-10
    • 2018-03-04
    相关资源
    最近更新 更多