为什么“getSharedPreferences”在单元测试中返回null?

时间:2018-05-29 12:15:40

标签: unit-testing kotlin sharedpreferences

我的课程是用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()
}

这是在演示者中调用的方法:

 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)不能为null     在   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。在我的考试课上。

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

2 个答案:

答案 0 :(得分:2)

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

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

并返回你需要的东西。

答案 1 :(得分:1)

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

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 */
    }
}