简体   繁体   English

如何使用 Mockito 模拟 SharedPreferences

[英]How to mock a SharedPreferences using Mockito

I have just read about Unit Instrumented Testing in Android and I wonder how I can mock a SharedPreferences without any SharedPreferencesHelper class on it like here我刚刚阅读了 Android 中的单元检测测试,我想知道如何在没有任何 SharedPreferencesHelper 类的情况下模拟 SharedPreferences,就像这里

My code is:我的代码是:

public class Auth {
private static SharedPreferences loggedUserData = null;
public static String getValidToken(Context context)
{
    initLoggedUserPreferences(context);
    String token = loggedUserData.getString(Constants.USER_TOKEN,null);
    return token;
}
public static String getLoggedUser(Context context)
{
    initLoggedUserPreferences(context);
    String user = loggedUserData.getString(Constants.LOGGED_USERNAME,null);
    return user;
}
public static void setUserCredentials(Context context, String username, String token)
{
    initLoggedUserPreferences(context);
    loggedUserData.edit().putString(Constants.LOGGED_USERNAME, username).commit();
    loggedUserData.edit().putString(Constants.USER_TOKEN,token).commit();
}

public static HashMap<String, String> setHeaders(String username, String password)
{
    HashMap<String, String> headers = new HashMap<String, String>();
    String auth = username + ":" + password;
    String encoding = Base64.encodeToString(auth.getBytes(), Base64.DEFAULT);
    headers.put("Authorization", "Basic " + encoding);
    return headers;
}

public static void deleteToken(Context context)
{
    initLoggedUserPreferences(context);
    loggedUserData.edit().remove(Constants.LOGGED_USERNAME).commit();
    loggedUserData.edit().remove(Constants.USER_TOKEN).commit();
}

public static HashMap<String, String> setHeadersWithToken(String token) {
    HashMap<String, String> headers = new HashMap<String, String>();
    headers.put("Authorization","Token "+token);
    return headers;
}
private static SharedPreferences initLoggedUserPreferences(Context context)
{
    if(loggedUserData == null)
        loggedUserData = context.getSharedPreferences(Constants.LOGGED_USER_PREFERENCES,0);
    return loggedUserData;
}}

Is is possible to mock SharedPreferences without creating other class on it?是否可以在不创建其他类的情况下模拟 SharedPreferences?

So, because SharedPreferences comes from your context , it's easy:因此,因为SharedPreferences来自您的context ,所以很容易:

final SharedPreferences sharedPrefs = Mockito.mock(SharedPreferences.class);
final Context context = Mockito.mock(Context.class);
Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);

// no use context

for example, for getValidToken(Context context) , the test could be:例如,对于getValidToken(Context context) ,测试可以是:

@Before
public void before() throws Exception {
    this.sharedPrefs = Mockito.mock(SharedPreferences.class);
    this.context = Mockito.mock(Context.class);
    Mockito.when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
}

@Test
public void testGetValidToken() throws Exception {
    Mockito.when(sharedPrefs.getString(anyString(), anyString())).thenReturn("foobar");
    assertEquals("foobar", Auth.getValidToken(context));
    // maybe add some verify();
}

The following example shows how you might create a unit test that uses a mock Context object such as shared preference.以下示例显示了如何创建使用模拟 Context 对象(例如共享首选项)的单元测试。

@RunWith(MockitoJUnitRunner.class)
public class MProfileTest {

   @Mock
   Context mockContext;
   @Mock
   SharedPreferences mockPrefs;
   @Mock
   SharedPreferences.Editor mockEditor;

   @Before
   public void before() throws Exception {

      Mockito.when(mockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mockPrefs);
      Mockito.when(mockContext.getSharedPreferences(anyString(), anyInt()).edit()).thenReturn(mockEditor);

      Mockito.when(mockPrefs.getString("YOUR_KEY", null)).thenReturn("YOUR_VALUE");
   }

   @Test
   public void anyTest() {
      // Any shared preference you can call
      // Assert.assertTrue();
      String val = _mockPrefs.getString("YOUR_KEY", null); // It returns YOUR_VALUE
   }
}

If you face any issues on importing mock framework just make sure you have added the depencencies in your app/build.gradle file.如果您在导入模拟框架时遇到任何问题,请确保您已在app/build.gradle文件中添加了app/build.gradle

https://developer.android.com/training/testing/unit-testing/local-unit-tests#setup https://developer.android.com/training/testing/unit-testing/local-unit-tests#setup


If you want to use real shared prefrence as your device by storing all the data in memory, follow the below code.如果您想通过将所有数据存储在内存中来使用真正的共享偏好作为您的设备,请按照以下代码操作。

Get the MockSharedPreference.java file from this Gist https://gist.github.com/aslamanver/f74a2b3d450fda251d47a0d38b44edb7从这个 Gist https://gist.github.com/aslamanver/f74a2b3d450fda251d47a0d38b44edb7获取 MockSharedPreference.java 文件

@Mock
Context mockContext;

MockSharedPreference mockPrefs;
MockSharedPreference.Editor mockPrefsEditor;

@Before
public void before() {

    mockPrefs = new MockSharedPreference();
    mockPrefsEditor = mockPrefs.edit();

    Mockito.when(mockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mockPrefs);
}

There is a better way to mock SharedPreferences, IMHO.有一种更好的方法来模拟 SharedPreferences,恕我直言。 I like Mockito, but it is unproductive to mock SharedPreferences in every test.我喜欢 Mockito,但在每次测试中都模拟 SharedPreferences 是徒劳的。

Luckily, we can use the shared-preferences-mock library.幸运的是,我们可以使用shared-preferences-mock库。 This library implements SharedPrefences on JVM, so it behaves like a real class.这个库在 JVM 上实现了 SharedPrefences,所以它的行为就像一个真正的类。 Moreover, it is possible to write local unit tests.此外,可以编写本地单元测试。

For your case:对于您的情况:

import com.github.ivanshafran.sharedpreferencesmock.SPMockBuilder;

class Test {
    private Context context;
    private SharedPreferences sharedPreferences;

    @Before
    public void setUp() {
        this.sharedPreferences = new SPMockBuilder().createSharedPreferences();
        this.context = Mockito.mock(Context.class);         
        Mockito.when(context.getSharedPreferences(Constants.LOGGED_USER_PREFERENCES,0))
            .thenReturn(sharedPreferences);
    }

    @Test
    public void test() {
        sharedPreferences.edit().putString(Constants.LOGGED_USERNAME, "admin").commit();
        String value = Auth.getLoggedUser(context);
        asssertEquals("admin", value);
    }

}

Add it to your root build.gradle at the end of repositories:将其添加到存储库末尾的根 build.gradle 中:

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

Add the dependency:添加依赖:

dependencies {
    testImplementation 'com.github.IvanShafran:shared-preferences-mock:1.0'
}

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

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