Android retrofit2 的 JUnit 测试给出空指针异常

Android JUnit test for retrofit2 giving null pointer exception

我已经使用 Mokito 为我的应用实施了 Junit 测试。我喜欢测试登录 Activity。但是得到 Nullpointer 异常。

登录Activity

    package com.example.activity;

import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.view.Gravity;
import android.view.View;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;

import com.example.R;
import com.example.api.APIClient;
import com.example.api.APIInterFace;
import com.example.api.apipojo.ChatListDataFinal;
import com.example.api.apipojo.GetCustomerIDResponse;
import com.example.api.apipojo.LoginRequest;
import com.example.api.apipojo.LoginSuccessRes;
import com.example.base.BaseActivity;
import com.example.customViews.CustomEditText;
import com.example.customViews.CustomTextView;
import com.example.helpers.PreferencesManager;
import com.example.utils.Constants;
import com.example.utils.Log;
import com.example.utils.Utils;
import com.google.gson.Gson;

import org.json.JSONObject;

import java.util.Objects;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class LoginActivity extends BaseActivity {

    private CustomEditText emailEditText, passwordEditText;
    private FrameLayout progressBarLayout;
    private CheckBox checkBox;
    CustomTextView rememberTextView;
    //   List<LoginSuccessRes.TenantUnit> tenantUnits;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login_activity);
        initializeViews();
    }

    @Override
    public void onBackPressed() {
        closeTheApp();
    }

    private void closeTheApp() {
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);
        try {
            finishAffinity();
            finish();
        } catch (Exception e) {
            e.printStackTrace();
        }

        this.overridePendingTransition(R.anim.enter, R.anim.exit);
    }

    public void getCustomerId(String email, final String pass) {


        showProgress(progressBarLayout);
      //  Log.e("apiInterFace >>",apiInterFace.toString());
        if (apiInterFace == null) {
            apiInterFace = APIClient.getAPIClient().create(APIInterFace.class);
        }
        Call<GetCustomerIDResponse> getCustomerIDResponseCall = apiInterFace.getCustomerId(email);
        final String finalEmail = email;
            getCustomerIDResponseCall.enqueue(new Callback<GetCustomerIDResponse>() {
                @Override
                public void onResponse(Call<GetCustomerIDResponse> call, Response<GetCustomerIDResponse> response) {
                    try {
                        ChatListDataFinal chatListDataFinal = null;
                        int resCode = response.raw().code();
                        hideProgress(progressBarLayout);
                        if ((resCode == 200) || (resCode == 201) || (resCode == 204)) {
                            GetCustomerIDResponse obj = response.body();
                            if (obj != null) {
                                if (obj.getSuccess()) {
                                    if (obj.getData().toString().equalsIgnoreCase("[]")) {

                                    } else {
                                        String customerId = obj.getData().get(0).toString();
                                        Log.e("customerId >>", customerId);
                                        prefManager.setStringValue(PreferencesManager.CUSTOMER_ID, customerId);
                                        loginToServer(finalEmail, pass, customerId);
                                    }


                                }


                            }

                        } else {
                            assert response.errorBody() != null;
                            JSONObject msgObj = new JSONObject(response.errorBody().string());
                            utilsErrorResHandle(LoginActivity.this, msgObj);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFailure(Call<GetCustomerIDResponse> call, Throwable t) {
                    Log.e("inside failure >>", t.getCause().toString());
                    hideProgress(progressBarLayout);
                }
            });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.loginTextView:
                loginRequest();
                break;
            case R.id.rememberTextView:
                // checkBox.performClick();
                showTermsPopup();
                break;
            case R.id.forgotPassTextView:
                Intent forgotPasswordIntent = new Intent(LoginActivity.this, ForgotPasswordActivity.class);
                startActivity(forgotPasswordIntent);
                break;
        }
    }

    public void showTermsPopup() {

        final View popupView = LoginActivity.this.getLayoutInflater().inflate(R.layout.terms_and_conditions_layout, null);

        final PopupWindow popupWindow = new PopupWindow(popupView,
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
        RelativeLayout layPopup = (RelativeLayout) popupView.findViewById(R.id.layPopup);
        LinearLayout layTerms = (LinearLayout) popupView.findViewById(R.id.layTerms);
        CustomTextView closeTextView = (CustomTextView) popupView.findViewById(R.id.closeTextView);
        CustomTextView termsTextView = (CustomTextView) popupView.findViewById(R.id.termsTextView);
        CustomTextView termsTitleView = (CustomTextView) popupView.findViewById(R.id.termsTitleTextView);
        termsTextView.setText(Constants.TERMS);
        closeTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                popupWindow.dismiss();
            }
        });
        layPopup.setPadding(0, widthSpace * 6, 0, 0);
        /*RelativeLayout.LayoutParams cntParentLayoutParams = (RelativeLayout.LayoutParams) layPopup.getLayoutParams();
        cntParentLayoutParams.setMargins(widthSpace * 6, widthSpace * 6, widthSpace * 6, widthSpace * 6);
        layPopup.setLayoutParams(cntParentLayoutParams);*/

        RelativeLayout.LayoutParams termsLayoutParams = (RelativeLayout.LayoutParams) layTerms.getLayoutParams();
        termsLayoutParams.setMargins(widthSpace * 4, widthSpace * 4, widthSpace * 4, widthSpace * 4);
        layTerms.setLayoutParams(termsLayoutParams);

        LinearLayout.LayoutParams termsTitleViewLayoutParams = (LinearLayout.LayoutParams) termsTitleView.getLayoutParams();
        termsTitleViewLayoutParams.setMargins(widthSpace * 2, widthSpace * 2, widthSpace * 6, widthSpace * 2);
        termsTitleView.setPadding(widthSpace * 2, widthSpace * 2, widthSpace * 2, widthSpace * 2);
        termsTitleView.setLayoutParams(termsTitleViewLayoutParams);

        FrameLayout.LayoutParams termsTextViewLayoutParams = (FrameLayout.LayoutParams) termsTextView.getLayoutParams();
        termsTextViewLayoutParams.setMargins(widthSpace * 2, 0, widthSpace * 2, widthSpace * 2);
        termsTextView.setPadding(widthSpace * 2, widthSpace * 2, widthSpace * 2, widthSpace * 2);
        termsTextView.setLayoutParams(termsTextViewLayoutParams);

        RelativeLayout.LayoutParams closeImageViewParams = (RelativeLayout.LayoutParams) closeTextView.getLayoutParams();
        closeImageViewParams.setMargins(widthSpace * 2, widthSpace * 2, widthSpace * 4, widthSpace * 2);
        closeImageViewParams.height = widthSpace * 4;
        closeImageViewParams.width = widthSpace * 4;
        closeTextView.setLayoutParams(closeImageViewParams);

        // If the PopupWindow should be focusable
        popupWindow.setFocusable(true);
        popupWindow.setTouchable(true);

        // If you need the PopupWindow to dismiss when when touched outside
        popupWindow.setBackgroundDrawable(new ColorDrawable());
        popupWindow.setAnimationStyle(R.style.Animation);
        popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);

    }


    public void initializeViews() {
        LinearLayout cntParentLayout = findViewById(R.id.cntParentLayout);
        ImageView logoImageView = findViewById(R.id.logoImageView);
        emailEditText = findViewById(R.id.emailEditText);
        passwordEditText = findViewById(R.id.passwordEditText);
        CustomTextView loginTextView = findViewById(R.id.loginTextView);
        checkBox = findViewById(R.id.checkBox);
        rememberTextView = findViewById(R.id.rememberTextView);
        String firstWord = "I accept";
        String lastWord = " Terms and Conditions";
        Spannable spannable = new SpannableString(firstWord + lastWord);
        spannable.setSpan(new ForegroundColorSpan(ContextCompat.getColor(LoginActivity.this, R.color.black_color)), 0, firstWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        spannable.setSpan(new ForegroundColorSpan(ContextCompat.getColor(LoginActivity.this, R.color.colorPrimary)), firstWord.length(), firstWord.length() + lastWord.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        rememberTextView.setText(spannable);

        CustomTextView forgotPassTextView = findViewById(R.id.forgotPassTextView);
        progressBarLayout = findViewById(R.id.progressBarLayout);

        RelativeLayout.LayoutParams cntParentLayoutParams = (RelativeLayout.LayoutParams) cntParentLayout.getLayoutParams();
        cntParentLayoutParams.setMargins(widthSpace * 6, widthSpace * 10, widthSpace * 6, widthSpace * 2);
        cntParentLayout.setLayoutParams(cntParentLayoutParams);

        LinearLayout.LayoutParams emailEditTextParams = (LinearLayout.LayoutParams) emailEditText.getLayoutParams();
        emailEditTextParams.setMargins(0, widthSpace * 6, 0, widthSpace * 2);
        emailEditText.setPadding(widthSpace * 2, widthSpace * 2, widthSpace * 2, widthSpace * 2);
        emailEditText.setLayoutParams(emailEditTextParams);

        LinearLayout.LayoutParams passwordEditTextParams = (LinearLayout.LayoutParams) passwordEditText.getLayoutParams();
        passwordEditTextParams.setMargins(0, widthSpace * 4, 0, widthSpace * 2);
        passwordEditText.setPadding(widthSpace * 2, widthSpace * 2, widthSpace * 2, widthSpace * 2);
        passwordEditText.setLayoutParams(passwordEditTextParams);

        LinearLayout.LayoutParams loginTextViewParams = (LinearLayout.LayoutParams) loginTextView.getLayoutParams();
        loginTextViewParams.setMargins(widthSpace * 4, widthSpace * 6, widthSpace * 4, widthSpace * 2);
        loginTextView.setPadding(widthSpace * 2, widthSpace * 2, widthSpace * 2, widthSpace * 2);
        loginTextView.setLayoutParams(loginTextViewParams);

        LinearLayout.LayoutParams checkBoxParams = (LinearLayout.LayoutParams) checkBox.getLayoutParams();
        checkBoxParams.setMargins(0, widthSpace * 4, widthSpace * 2, widthSpace * 4);
        checkBoxParams.height = widthSpace * 5;
        checkBoxParams.width = widthSpace * 5;
        checkBox.setLayoutParams(checkBoxParams);

        RelativeLayout.LayoutParams logoImageViewParams = (RelativeLayout.LayoutParams) logoImageView.getLayoutParams();
        logoImageViewParams.setMargins(widthSpace * 6, widthSpace * 4, widthSpace * 6, widthSpace * 6);
        logoImageViewParams.height = widthSpace * 8;
        logoImageView.setLayoutParams(logoImageViewParams);

        forgotPassTextView.setPadding(widthSpace * 2, 0, widthSpace * 2, widthSpace * 6);

        loginTextView.setOnClickListener(this);
        rememberTextView.setOnClickListener(this);
        forgotPassTextView.setOnClickListener(this);

    }

    private void loginRequest() {
        String email = Objects.requireNonNull(emailEditText.getText()).toString().trim();
        String pass = Objects.requireNonNull(passwordEditText.getText()).toString().trim();
        email = email.toLowerCase();
        if (!Utils.isNetWorkAvailable(this)) {
            showMessage(this, this.getResources().getString(R.string.no_internet));
        } else if (TextUtils.isEmpty(email)) {
            showMessage(this, this.getResources().getString(R.string.please_enter_email));
        } else if (!Utils.isEmailValid(email)) {
            showMessage(this, this.getResources().getString(R.string.please_enter_valid_email));
        } else if (TextUtils.isEmpty(pass)) {
            showMessage(this, this.getResources().getString(R.string.please_enter_pass));
        } else if (!checkBox.isChecked()) {
            showMessage(this, this.getResources().getString(R.string.please_accept_terms));
        } else {
            if (Utils.isNetWorkAvailable(this)) {
                showProgress(progressBarLayout);

                getCustomerId(email, pass);


            } else {
                showMessage(this, this.getResources().getString(R.string.no_internet));
            }
        }
    }

    public void loginToServer(String email, String pass, String custId) {
        LoginRequest loginReq = new LoginRequest();
        loginReq.setUsername(email);
        loginReq.setPassword(pass);
        Call<LoginSuccessRes> loginCall = apiInterFace.requestLogin(Constants.PLATFORM, loginReq, custId);
        loginCall.enqueue(new Callback<LoginSuccessRes>() {
                @Override
                public void onResponse(Call<LoginSuccessRes> call, Response<LoginSuccessRes> response) {
                    try {
                        int resCode = response.raw().code();
                        if ((resCode == 200) || (resCode == 201) || (resCode == 204)) {
                            if (response.body().getData().getUserRole().equalsIgnoreCase("tenant")) {
                                int userId = response.body().getData().getUser().getId();
                                String userToken = response.body().getData().getToken();
                                prefManager.setIntValue(PreferencesManager.LOGIN_USER_ID, userId);
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_TOKEN, userToken);
                                //  prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_IMAGE, response.body().getData().getUser().getProfile_pic());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_ROLE, response.body().getData().getUserRole());
                                String email = response.body().getData().getUser().getUser().getEmail();
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_EMAIL, email);
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_TYPE, response.body().getData().getUser().getType());
                                // prefManager.setStringValue(PreferencesManager.LOGIN_USER_ROLE_TYPE, response.body().getData().getUser().getRole_type());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_ADDRESS, response.body().getData().getUser().getAddress().get(0).getAddress().getAddress1());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_ADDRESS_TYPE, response.body().getData().getUser().getAddress().get(0).getAddress().getAddressType());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_CITY, response.body().getData().getUser().getAddress().get(0).getAddress().getCity());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_STATE, response.body().getData().getUser().getAddress().get(0).getAddress().getState());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_COUNTRY, response.body().getData().getUser().getAddress().get(0).getAddress().getCountryCode());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_ZIPCODE, response.body().getData().getUser().getAddress().get(0).getAddress().getZipcode());
                                String fName = response.body().getData().getUser().getUser().getFirstName();
                                String lName = response.body().getData().getUser().getUser().getLastName();
                                String mobile = response.body().getData().getUser().getUser().getMobileNumber();
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_F_NAME, fName);
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_L_NAME, lName);
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_MOBILE, mobile);
                                // prefManager.setStringValue(PreferencesManager.LOGIN_USER_COI_FILE, response.body().getData().getUser().getCoi_file());
                                //  prefManager.setStringValue(PreferencesManager.LOGIN_USER_COI_FILE_EXPIRY, response.body().getData().getUser().getUser().getCoi_expiry_date());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_UNIQUE_NAME, response.body().getData().getUser().getUser().getRoleName());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_RECOVERY_EMAIL, response.body().getData().getUser().getUser().getRecoveryEmail());
                                prefManager.setStringValue(PreferencesManager.LOGIN_USER_PROFILE_ROLE_NAME, response.body().getData().getUser().getUser().getRoleName());
                                prefManager.setBooleanValue(PreferencesManager.LOGIN_USER_ACTIVE, response.body().getData().getUser().getIsActivated());
                                String tenantUnits = response.body().getData().getUser().getTotalUnits();
                                String total_square_feet = response.body().getData().getUser().getTotalSquareFeet();
                                prefManager.setStringValue(PreferencesManager.TENANT_UNIT, tenantUnits);
                                Gson gson = new Gson();
                                String loginResponse = gson.toJson(response.body());
                                prefManager.setStringValue(PreferencesManager.LOGIN_RESPONSE, loginResponse);
                                Intent dashBoardIntent = new Intent(LoginActivity.this, TutorialActivity.class);
                                dashBoardIntent.putExtra("isFromLogin", true);
                                dashBoardIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                                dashBoardIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                                startActivity(dashBoardIntent);
                                finish();
                            }


                        } else {
                            assert response.errorBody() != null;
                            JSONObject msgObj = new JSONObject(response.errorBody().string());
                            utilsErrorResHandle(LoginActivity.this, msgObj);
                        }
                        hideProgress(progressBarLayout);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onFailure(Call<LoginSuccessRes> call, Throwable t) {
                    Log.e("inside failure>>", t.getMessage());
                    hideProgress(progressBarLayout);

                }
            });
        }

}

测试Activity

public class LoginActivityTest1 {
    String email="qa04tenantttt@mailinator.com", password="12345678",custID="qa2";
    @Mock
    APIInterFace apiInterFace;

    @InjectMocks
    LoginActivity loginActivity;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }


    @Test
    public void testOnBackPressed() throws Exception {
        loginActivity.onBackPressed();
    }

    @Test
    public void testGetCustomerId() throws Exception {
        when(apiInterFace.requestLogin(anyString(), any(), anyString())).thenReturn(null);
        when(apiInterFace.getCustomerId(anyString())).thenReturn(null);
        loginActivity.getCustomerId(email, password);
    }

    @Test
    public void testLoginToServer() throws Exception {
        when(apiInterFace.requestLogin(anyString(), any(), anyString())).thenReturn(null);

        loginActivity.loginToServer(email, password, custID);
    }


    @Test
    public void testCreateFolder() throws Exception {
        LoginActivity.createFolder();
    }

    @Test
    public void testShowProgress() throws Exception {
        LoginActivity.showProgress(null);
    }

    @Test
    public void testHideProgress() throws Exception {
        LoginActivity.hideProgress(null);
    }
}

错误

java.lang.NullPointerException
        at com.fyxttenant.activity.LoginActivity.loginToServer(LoginActivity.java:298)
        at com.fyxttenant.activity.LoginActivityTest1.testLoginToServer(LoginActivityTest1.java:66)
    

java.lang.NullPointerException
    at com.fyxttenant.activity.LoginActivity.getCustomerId(LoginActivity.java:92)
    at com.fyxttenant.activity.LoginActivityTest1.testGetCustomerId(LoginActivityTest1.java:53)

编辑 1: 改造调用为空,而我 运行 测试 class.

编辑 2 APIClient.java:

public class APIClient {
 private static final String BASE_URL = "https://example.io/"; 
    private static Retrofit retrofit = null;
     public static Retrofit getAPIClient() {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        final OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .readTimeout(60, TimeUnit.SECONDS)
                .connectTimeout(300, TimeUnit.SECONDS)
                .build();
        if (retrofit == null) {
            Gson gson = new GsonBuilder()
                    .setLenient()
                    .create();

            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .client(okHttpClient)
                    .build();
        }

        return retrofit;
    }

}

基础Activity

 public abstract class BaseActivity extends AppCompatActivity implements View.OnClickListener {
        public int height = 0, width = 0,widthSpace = 0;
        public static LayoutInflater mInflater = null;
        protected PreferencesManager prefManager = null;
        public APIInterFace apiInterFace = null;
        public static double selectedLocationLatitude = 0,selectedLocationLongitude = 0;
        public static String selectedAddress = "",selectedCity = "", selectedCountry = "";
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            initializeConstants();
        }
        @Override
        protected void onResume() {
            super.onResume();
        }
        @Override
        protected void onStop() {
            super.onStop();
        }
        private void initializeConstants() {
            Point screenSizePoints = Utils.getDeviceDynamicPixelSize(this);
            height = screenSizePoints.y;
            width = screenSizePoints.x;
            mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
           widthSpace = (int)(width * 0.015);
            if (prefManager == null) {
                prefManager = PreferencesManager.getInstance(this);
            }
            if (apiInterFace == null) {
                apiInterFace = APIClient.getAPIClient().create(APIInterFace.class);
            }
        }
        public static void createFolder(){
            File file = new File(Environment.getExternalStorageDirectory(), "test");
            if(!file.exists()){
                file.mkdir();
            }
        }
       public static void showProgress(FrameLayout layout) {
            if(layout != null) {
                layout.setVisibility(View.VISIBLE);
            }
        }
        public static void hideProgress(FrameLayout layout) {
            if(layout != null) {
                layout.setVisibility(View.GONE);
            }
        }
       @Override
        protected void onPause() {
            super.onPause();
        }
     }

在您的单元测试中,您正在调用 apiInterFace.requestLogin 到 return null:

when(apiInterFace.requestLogin(anyString(), any(), anyString())).thenReturn(null);

LoginActivity.loginToServer中调用apiInterFace.requestLogin,其return用于调用enqueue函数:

Call<LoginSuccessRes> loginCall = apiInterFace.requestLogin(Constants.PLATFORM, loginReq, custId);
loginCall.enqueue(new Callback<LoginSuccessRes>() { ... }

因此,当您尝试在 loginCall 变量中的 Call<LoginSuccessRes> 的空实例上调用 enqueue 函数时,您会得到一个 NullPointerException