Sharedpreference.edit() 在 JUnit 测试 + Mockito 中给出 NullPointerException

Sharedpreference.edit() gives NullPointerException in JUnit Testing + Mockito

用于计算时间的 Junit 测试 class:

{
    private HomeActivity homeActivity;
    private SessionManager sessionManager;
    private String result_time;

    @Mock
    Context context;

    @Mock
    SharedPreferences.Editor editor;

    @Mock
    SharedPreferences sharedPreferences;

    @Before
    public void Setup()
    {

         homeActivity = new HomeActivity();
         sessionManager = new SessionManager(context);
        when(context.getSharedPreferences(anyString(), anyInt()))
                .thenReturn(sharedPreferences);
        when(sharedPreferences.edit()).thenReturn(editor);
        when(editor.putString(anyString(), anyString())).thenReturn(editor);
    }

    @Test
    public void test_calculateTimeAgo()
    {
        when(sessionManager.getLastSyncDateTime()).thenReturn("13-07-2020 20:22");
        result_time = homeActivity.CalculateAgoTime();
        assertFalse(result_time.isEmpty());
    }
}

Java代码功能:

   public String CalculateAgoTime() {
        String finalTime = "";

        String syncTime = sessionManager.getLastSyncDateTime();

        SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm", Locale.getDefault());
        ParsePosition pos = new ParsePosition(0);
        long then = formatter.parse(syncTime, pos).getTime();
        long now = new Date().getTime();

        long seconds = (now - then) / 1000;
        long minutes = seconds / 60;
        long hours = minutes / 60;
        long days = hours / 24;

        String time = "";
        long num = 0;
        if (days > 0) {
            num = days;
            time = days + " " + context.getString(R.string.day);
        } else if (hours > 0) {
            num = hours;
            time = hours + " " + context.getString(R.string.hour);
        } else if (minutes >= 0) {
            num = minutes;
            time = minutes + " " + context.getString(R.string.minute);
        }
//      <For Seconds>
//      else {
//            num = seconds;
//            time = seconds + " second";
//      }
        if (num > 1) {
            time += context.getString(R.string.s);
        }
        finalTime = time + " " + context.getString(R.string.ago);

        sessionManager.setLastTimeAgo(finalTime);

        return finalTime;
    }

我使用 SessionManager class 来维护所有 SharedPref 值。

构造函数:

 public SessionManager(Context context) {
        this._context = context;
        pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
        editor = pref.edit();
    }

editor = pref.edit();

当我 运行 我的 UnitTest class.

时,这一行给出 NullPointerException

Getter & Setter 对于 SharedPef:

public String getLastSyncDateTime() {
        return pref.getString(LAST_SYNC_SUCCESS_DATE_TIME, "- - - -");
    }  //getting the sync value  and time and saving in the sharedpref

    public void setLastSyncDateTime(String lastPulledDateTime) {
        editor.putString(LAST_SYNC_SUCCESS_DATE_TIME, lastPulledDateTime);
        editor.commit();
    }

我不确定这个。但是你错过了一行代码来注入模拟注释变量可能是由于发生了异常。

@Before 方法中需要包含的代码:

MockitoAnnotations.initMocks(这个);

也许这会对你有所帮助。

参考:https://gist.github.com/marcouberti/500621c4646f5fdb8d69721d5186cac3

CalculateTimeAgo_Unit_Test.class

package io.intelehealth.client;

import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;

import com.parse.Parse;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;

import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import app.intelehealth.client.activities.homeActivity.HomeActivity;
import app.intelehealth.client.app.IntelehealthApplication;
import app.intelehealth.client.utilities.SessionManager;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;


/**
 * Created by Prajwal Waingankar
 * on 13-Jul-20.
 * Github: prajwalmw
 */

@RunWith(MockitoJUnitRunner.class)
public class CalculateTimeAgo_UnitTest {
    private HomeActivity homeActivity;
    private SessionManager sessionManager;
    private SharedPreferences sharedPreferences;
    private Context context;
    private SharedPreferences.Editor editor;
    private SimpleDateFormat simpleDateFormat;
    private ParsePosition parsePosition;
    private Locale locale;
    CalculateTimeAgo_UnitTest cal;
    private int PRIVATE_MODE = 0;
    private static final String PREF_NAME = "Intelehealth";


    @Before
    public void Setup()
    {
        context = mock(Context.class);
        simpleDateFormat = mock(SimpleDateFormat.class);
        parsePosition = mock(ParsePosition.class);

        sharedPreferences = mock(SharedPreferences.class);
        editor = mock(SharedPreferences.Editor.class);

        when(context.getSharedPreferences(PREF_NAME, PRIVATE_MODE)).thenReturn(sharedPreferences);
        when(sharedPreferences.edit()).thenReturn(editor);
        sessionManager = new SessionManager(context);
        homeActivity = new HomeActivity(); //It is a java class so no mocking of this class.

    }

    @Test
    public void test_calculateTimeAgo()
    {
//        when(simpleDateFormat.parse(anyString(), any(ParsePosition.class)).setTime()).thenReturn();
//        when(simpleDateFormat.parse(anyString(), any(ParsePosition.class)).getTime()).thenReturn(4544544L);
        when(sessionManager.getLastSyncDateTime()).thenReturn("13-07-2020 20:22");

        String result_time = homeActivity.CalculateAgoTime(sessionManager);
        assertFalse(result_time.isEmpty());
    }
}

我的 SharedPreferences 问题已经解决。我想到了使用 mock(Android_Dependency.class) 格式而不是注解@mock 基于流。

此外,在 setup() 中, 我以以下格式创建了模拟:

  • 上下文

  • 共享偏好

  • 编辑

  • context.getsharedpreferences

  • sharedpreferences.edit()

  • sessionmanager 实例创建

  • homeactivity 实例创建。

当我 debugged 单元测试并逐行检查每个代码以找到空异常时,我意识到了我的错误。

我注意到 null 异常位于:

context.getSharedPrefernces()

然后,我意识到单元测试是按照代码编写的方式进行的。按照在单元测试 class 代码中编写的方式逐行创建模拟。

Make sure to create mocks based on their Heirarchy of exection.