0

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.

Kavita Patil
  • 1,784
  • 1
  • 17
  • 30
  • @second Sorry for the inconvenience. I have updated the file. – Kavita Patil Jul 29 '19 at 09:26
  • The exception seems to be related to how you spawn certain things in an `android environment`. Has probably nothing to do with `mockito` per se, but I am also not sure how you would handle that stuff in an unit test environment. -- The assigning in the setup should not be necesarry, a simply rule based test with annotations does work fine without it. – second Jul 29 '19 at 09:26
  • If I understood correctly it worked before, so the best option might be to just follow `Maciej Kowalski` advice and set up your mocks manually instead. – second Jul 29 '19 at 09:33
  • @second, `set up your mocks manually instead.` can you please elaborate this term. How can I mock LoginActivity by setting up mokes manually? How to inject mocks using setter? Should I do that for LoginActivity? – Kavita Patil Jul 29 '19 at 09:45
  • 1
    I added an example as an answer (as code in the comments can't be properly formatted). See it as an extension to `Maciej Kowalski` answer. – second Jul 29 '19 at 09:52

2 Answers2

1

You are not injecting the mock anywhere in your tests case. I assume a normal instance is created in constructor / factory.

Either use a setter of the SUT or make Mockito inject it for you:

@InjectMocks
LoginActivity loginActivity;

Using @Mock only is not enough.

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • @MaciejKowaski Thanks for the reply, after using `@InjectMocks` I am getting below error, `org.mockito.exceptions.misusing.InjectMocksException: Cannot instantiate @InjectMocks field named 'loginActivity' of type 'class com.mytest.LoginActivity'. You haven't provided the instance at field declaration so I tried to construct the instance. However the constructor or the initialization block threw an exception : Can't create handler inside thread that has not called Looper.prepare()` – Kavita Patil Jul 29 '19 at 08:37
  • 2
    Most likely that class does not have a public no-arg constructor. You need to inject the mock using a setter then – Maciej Kowalski Jul 29 '19 at 08:47
  • Hi @Maciej Kowalski how to deal with `MockWebServer` in below case, https://stackoverflow.com/q/58367198/6532155 ? Please check this question. – Kavita Patil Oct 14 '19 at 20:21
1

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.

second
  • 4,069
  • 2
  • 9
  • 24
  • It worked like a charm. Thanks for the reply. Still I would like to know the reason behind keeping `loginActivity.fingerPrintHelper = fingerPrintHelper` line. As we are already doing `@Mock FingerPrintHelper fingerPrintHelper;` why do we need to add `loginActivity.fingerPrintHelper = fingerPrintHelper` line inside `setUp()` – Kavita Patil Jul 29 '19 at 10:06
  • 1
    Added a short explanation, hope that makes it clearer. – second Jul 29 '19 at 10:12
  • Hi @second , Please check this question too https://stackoverflow.com/q/58367198/6532155 – Kavita Patil Oct 14 '19 at 20:18