JUnit Testing in Android Studio with Firebase

2019-06-25 23:57发布

问题:

I want to write a Unit test for this class in Android Studio, but I am having problem creating test to cover usersignin() and getSignedinUserprofile() because of the use of Firebase. Does anyone have any experience with this?

public class LoginActivity extends AppCompatActivity implements View.OnClickListener{


private Button buttonSignIn;
private EditText editTextEmail;
private EditText editTextPassword;
private TextView textViewSignUp;

private ProgressDialog mProgressDialog;
private FirebaseAuth mfireBaseAuth;
private DatabaseReference mDatabase;
private String userID;
private FirebaseUser firebaseUser;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    FirebaseApp.initializeApp(this);

    mfireBaseAuth = FirebaseAuth.getInstance();
    mDatabase = FirebaseDatabase.getInstance().getReference();
    mProgressDialog = new ProgressDialog(this);
    editTextEmail = (EditText) findViewById(R.id.editTextEmail);
    editTextPassword = (EditText) findViewById(R.id.editTextPassword);
    buttonSignIn = (Button) findViewById(R.id.buttonSignIn);
    textViewSignUp = (TextView) findViewById(R.id.textViewSignUp);

    buttonSignIn.setOnClickListener(this);
    textViewSignUp.setOnClickListener(this);

}

@Override
public void onClick(View v) {
    if(v == buttonSignIn){
        usersignin();}
    if(v==textViewSignUp){
        startActivity(new Intent(this, RegisterActivity.class));}


}

public void usersignin() {

    String email = editTextEmail.getText().toString().trim();
    String password = editTextPassword.getText().toString().trim();

    if(TextUtils.isEmpty(email)){
        Toast.makeText(this, "Please enter Email", Toast.LENGTH_SHORT).show();
        return;
    }

    if(TextUtils.isEmpty(password)){
        Toast.makeText(this, "Please enter password", Toast.LENGTH_SHORT).show();
        return;
    }

    mProgressDialog.setMessage("Logging in. Please wait...");
    mProgressDialog.show();
    mfireBaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
        @Override
        public void onComplete(@NonNull Task<AuthResult> task) {
            mProgressDialog.dismiss();
            if(task.isSuccessful()){
                getSignedInUserProfile();
            }
        }
    });
}

public void getSignedInUserProfile() {

    DatabaseReference reference = mDatabase;//.child("eduback-2feef");
    firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
    userID = firebaseUser.getUid();
    reference.child("Users").child(userID).child("User info").addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            User user = dataSnapshot.getValue(User.class);
            if(user != null) {
                // Save if the user is student or prof in shared prefs.
                PreferenceHelper helper = new PreferenceHelper(getBaseContext());
                helper.setIsStudent(user.isStudent);
                checkStudentOrProfessor(user);
            }

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            // Ups vis error
        }
    });
}

public void checkStudentOrProfessor(User user) {

    Intent i;
    if (user.isStudent ) {
        i = new Intent(this, MainActivityStudent.class);
    } else {
        i = new Intent(this, MainActivityProfessor.class);
    }
    startActivity(i);
}

回答1:

You can use Mockito and PowerMockito to mock Firebase dependencies. For mocking static functions (like FirebaseDatabase.getInstance()) PowerMockRunner must be used to run the test but it can delegate to different runner later.

package com.test.firebasetest;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(JUnit4.class)
@PrepareForTest({ FirebaseDatabase.class})
public class LoginActivityTest {

  private DatabaseReference mockedDatabaseReference;

  @Before
  public void before() {
    mockedDatabaseReference = Mockito.mock(DatabaseReference.class);

    FirebaseDatabase mockedFirebaseDatabase = Mockito.mock(FirebaseDatabase.class);
    when(mockedFirebaseDatabase.getReference()).thenReturn(mockedDatabaseReference);

    PowerMockito.mockStatic(FirebaseDatabase.class);
    when(FirebaseDatabase.getInstance()).thenReturn(mockedFirebaseDatabase);
  }

  @Test
  public void getSignedInUserProfileTest() {
    when(mockedDatabaseReference.child(anyString())).thenReturn(mockedDatabaseReference);

    doAnswer(new Answer<Void>() {
      @Override
      public Void answer(InvocationOnMock invocation) throws Throwable {
        ValueEventListener valueEventListener = (ValueEventListener) invocation.getArguments()[0];

        DataSnapshot mockedDataSnapshot = Mockito.mock(DataSnapshot.class);
        //when(mockedDataSnapshot.getValue(User.class)).thenReturn(testOrMockedUser)

        valueEventListener.onDataChange(mockedDataSnapshot);
        //valueEventListener.onCancelled(...);

        return null;
      }
    }).when(mockedDatabaseReference).addListenerForSingleValueEvent(any(ValueEventListener.class));

    new LoginActivity().getSignedInUserProfile();

    // check preferences are updated
  }

}

You need to add appropriate dependencies to you module build.gradle:

testCompile 'junit:junit:4.12'
testCompile 'org.powermock:powermock:1.6.5'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'