Search code examples
javaandroidmockitoandroid-testingtestcase

Mockito error- There were zero interactions with this mock Android


I am getting Wanted but not invoked. There were zero interactions with this mock error for checkFingerPrintWhenTouchIdEnabled() method at line verify(fingerPrintHelper, times(1)).initializeFingerPrint(any()); . Even I have mocked the object & while debugging initializeFingerPrint(..) function gets called.

Below is the function which I want to test,

@RequiresApi(Build.VERSION_CODES.M)
public void checkFingerPrint() {
    if (fingerPrintHelper.isDeviceReadyForFingerPrint()) {
        boolean isFingerPrintEnable = sharedPreference.getBoolean(SpKeys.KEY_FINGER_PRINT, false);
        if (isFingerPrintEnable) {
            fingerPrintHelper.initializeFingerPrint(this);
        }
    } else {
        sharedPreference.putBoolean(SpKeys.KEY_FINGER_PRINT, false).commit();
    }
}

LoginActvity.java

public class LoginActivity extends AppCompatActivity {
public FingerPrintHelper fingerPrintHelper;
ActivityLoginBinding binding;
private LoginViewModel loginViewModel;
private SharedPreferenceManager sharedPreferenceManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    sharedPreferenceManager = new SharedPreferenceManager(getApplicationContext(), SpKeys.MY_SP);
    fingerPrintHelper = new FingerPrintHelper(this);
    binding = DataBindingUtil.setContentView(this, R.layout.activity_login);
    loginViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
    binding.setViewModel(loginViewModel);
    binding.setLifecycleOwner(this);

    checkFingerPrint();
}


@RequiresApi(Build.VERSION_CODES.M)
public void checkFingerPrint() {
    if (fingerPrintHelper.isDeviceReadyForFingerPrint()) {
        boolean isFingerPrintEnable = sharedPreferenceManager.getBoolean(SpKeys.KEY_FINGER_PRINT, false);
        if (isFingerPrintEnable) {
            fingerPrintHelper.initializeFingerPrint(this);
        }
    } else {
        sharedPreferenceManager.setBoolean(SpKeys.KEY_FINGER_PRINT, false);
    }
}
}

I am writing both positive and negative test cases for this function whereas checkFingerPrintWhenTouchIdDisabled() test works fine, but I am getting error for checkFingerPrintWhenTouchIdEnabled() test function Please refer the below test class

LoginActivityTest.java

public class LoginActivityTest {

LoginActivity loginActivity;
@Mock
FingerPrintHelper fingerPrintHelper;
@Rule
public ActivityTestRule<LoginActivity> loginActivityRule = new ActivityTestRule<>(
        LoginActivity.class);
Context context;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    loginActivity = loginActivityRule.getActivity();
    context = getInstrumentation().getTargetContext();
}

@Test
public void checkFingerPrintWhenTouchIdDisabled() {

    SharedPreferences sharedPreferences = context.getSharedPreferences(SpKeys.MY_SP, Context.MODE_PRIVATE);
    when(fingerPrintHelper.isDeviceReadyForFingerPrint()).thenReturn(false);
    loginActivity.checkFingerPrint();
    Assert.assertFalse(sharedPreferences.getBoolean(SpKeys.KEY_FINGER_PRINT, false));
    verify(fingerPrintHelper, never()).initializeFingerPrint(any());

}
@Test
public void checkFingerPrintWhenTouchIdEnabled() {

    SharedPreferences sharedPreferences = context.getSharedPreferences(SpKeys.MY_SP, Context.MODE_PRIVATE);
    SharedPreferences.Editor preferencesEditor = sharedPreferences.edit();
    when(fingerPrintHelper.isDeviceReadyForFingerPrint()).thenReturn(true);
    preferencesEditor.putBoolean(SpKeys.KEY_FINGER_PRINT, true).commit();

    loginActivity.checkFingerPrint();

    /* Below verification for `initializeFingerPrint()` is throwing error as,
    Actually, there were zero interactions with this mock. error,
    Even I have mock the object & while debugging the method is getting invoked also.
    If I debug my code it calls this function but in test cases it shows above error
    */
    verify(fingerPrintHelper, times(1)).initializeFingerPrint(any());
}
}

Then why am I getting the zero interaction error for my test cases? What could be the issue, any help is appreciated.

Thanks in advance.


Solution

  • Try the following to setup your mocks manually (without using annotations):

    @Before
    public void setUp() {
        loginActivity = loginActivityRule.getActivity();
        loginActivity.fingerPrintHelper = Mockito.mock(FingerPrintHelper.class);
        // ...
    }
    

    If loginAcitivy could be created succesfully before, you should not face a problem now.
    And fingerPrintHelper seems to be public anyway so its easy to set.
    But in case you want to do it properly you could just provide a setter.


    Or if you want to keep the annotation to create fingerPrintHelper.

    @Mock
    FingerPrintHelper fingerPrintHelper;
    
    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        loginActivity = loginActivityRule.getActivity();
        loginActivity.fingerPrintHelper = fingerPrintHelper;
        // ...
    }
    

    Still I would like to know the reason behind keeping loginActivity.fingerPrintHelper = fingerPrintHelper line.

    A mock does not magically attach itself to any other object.

    @InjectMocks would do that for you, but Mockito does not seem be able to handle the creation of your LoginActivity on its own.

    So the only thing you can do is to manually pass the mock to the object under test.