0

I'm trying run a unit test with Mockito, but I have a helper method where I want to use a real class:

public static Location fromCoordinates(float latitude, float longitude){
    Location result = new Location("");
    result.setLatitude(latitude);
    result.setLongitude(longitude);

    return result;
}

The method above currently causes a "Method ... not mocked." error as described here, it gives a suggestion on how to use default values, but that's not going to work for me since that causes the latitude and longitude to return 0 afterwards.

I also tried adding Mockito.mock(Location.class, CALLS_REAL_METHODS); at the beginning of my test which appears to have no effect.

How can I configure my test to use the real Location class while still using mockito to mock the others?

[Edit] For context, this is the unit test in question

@Test
public void OpensCenteredInLocation() {

    Location l = Mockito.mock(Location.class, CALLS_REAL_METHODS);

    //When the user starts the app
    LocationManager m = Mockito.mock(LocationManager.class);
    Location initial = LocationHelper.fromCoordinates(10, 15); //<--it fails here
    doReturn(initial).when(m).getLastKnownLocation(any(String.class));
    MyApp main = new MyApp(m);

    //Then it should open with the map centered in the user's location
    Assert.assertEquals(10, main.CameraPosition.longitude, 0);
    Assert.assertEquals(15, main.CameraPosition.longitude, 0);
}

When it fails, it throws java.lang.RuntimeException: Method setLatitude in android.location.Location not mocked. See http://g.co/androidstudio/not-mocked for details.

Eduardo Wada
  • 2,606
  • 19
  • 31
  • 1
    Mockito cannot mock static methods. You'd need something like PowerMockito for that. But a bigger question is, what are you trying to test where you'd need a mock `Location` object in the first place? – Jordan Mar 05 '20 at 21:23
  • I don't need a mock Location and that's the problem, I need mockito to allow me to call the real constructor, the "Method ... not mocked" message seems to be caused by the `new Location("")` call – Eduardo Wada Mar 05 '20 at 21:27
  • 1
    The `fromCoordinates` is a static method, so you shouldn't need to construct a new `Location` object at all. Just call `Location.fromCoordinates(...)` where needed. Are there other, non-static methods on `Location` that you need to have mocked? – Jordan Mar 05 '20 at 21:37
  • @Jordan that's exactly what my test is doing, it throws an exception at `new Location("")` which is part of the `fromCoordinates` method I wrote, I can't find a `android.location.Location.fromCoordinates` method, the one displayed in the question is `MyApp.LocationHelper.fromCoordinates` (my own class) – Eduardo Wada Mar 05 '20 at 22:13
  • As `@Jordan` pointed out you might want to use `PowerMockito` for that. Or you replace the `Location` object from android with one of your own. As the link describes it you do not have the option to use the real object for your test. – second Mar 05 '20 at 22:31
  • Using `Roboelectrics` might also be an option, as this [answer](https://stackoverflow.com/a/33786031/11514534) points out. – second Mar 05 '20 at 22:39

1 Answers1

0

I think the real problem is not because fromCoordinates method is static, in my opinion the real problem is because Location is a built-in Android class.

In fact when you run a unit test, it's being run on your computer, not on an Android device. So you cannot use the built-in Android classes.

Take a look at the android documentation

And then according to this doc told you that you could add to your build.gradle file

android {
  ...
  testOptions {
    unitTests.returnDefaultValues = true
  }
}

This prevents the android classes from throwing exceptions when you try to use them, but note that what this does is to

Change the behavior so that methods instead return either null or zero