Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock a method with an object parameter with Mockito

In my unit test i want to mock the interaction with elasticsearch by doing the following

when(cityDefinitionRepository.findCitiesNearby(geoPoint, SOURCE, 2)).thenReturn(cityDefinitionsArrival);
when(cityDefinitionRepository.findCitiesNearby(geoPoint2, SOURCE, 2)).thenReturn(cityDefinitionsDeparture);
SearchResult results = benerailService.doSearch(interpretation, 2, false);

the doSearch method contains

departureCityDefinitions = cityDefinitionRepository.findCitiesNearby(geo, SOURCE, distance);

When i debug my code i see that mockito is called in my doSearch method but it does not return the cityDefinitionsArrival object. This is probably because geoPoint and geo are two different objects.

The geoPoint and geo object are both elasticsearch GeoPoints which contain the same latitude and longitude.

I managed to get this to work by doing

when(cityDefinitionRepository.findCitiesNearby(any(geoPoint.getClass()), eq(SOURCE), eq(2))).thenReturn(cityDefinitionsArrival);
when(cityDefinitionRepository.findCitiesNearby(any(geoPoint2.getClass()), eq(SOURCE), eq(2))).thenReturn(cityDefinitionsDeparture);

But now it ignores my latitude and longitude values and accepts any object of the GeoPoint class. This is a problem because in my doSearch method i have two usages of the findCitiesNearby, each with different latitude and longitude and I need to mock them both individually.

Is this possible with Mockito?

The cityDefinitionsArrival and cityDefinitionsDeparture are both ArrayLists, the SOURCE is a String value and the geo and geoPoint object:

GeoPoint geoPoint = new GeoPoint(50.850449999999995, 4.34878);
GeoPoint geoPoint2 = new GeoPoint(48.861710, 2.348923);

double lat = 50.850449999999995;
double lon = 4.34878;
GeoPoint geo = new GeoPoint(lat, lon);

double lat2 = 48.861710;
double lon2 = 2.348923;
GeoPoint geo2 = new GeoPoint(lat2, lon2);
like image 849
Glenn Van Schil Avatar asked Jan 04 '16 09:01

Glenn Van Schil


People also ask

How can specify the mock Behaviour of an object?

When you create a mock, you create an associated behavior object that controls mock behavior. Use this object to define mock method and property behavior (stub). For more information on creating a mock, see Create Mock Object.

What is mock object in Mockito?

The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called.


1 Answers

Use argThat:

public final class IsSameLatLong extends ArgumentMatcher<GeoPoint> {

  private final GeoPoint as;

  public IsSameLatLong(GeoPoint as) {
      this.as = as;
  }

  //some sensible value, like 1000th of a second i.e. 0° 0' 0.001"
  private final static double EPSILON = 1.0/(60*60*1000); 

  private static boolean closeEnough(double a, double b) {
     return Math.abs(a - b) < EPSILON;
  }

  public boolean matches(Object point) {
      GeoPoint other = (GeoPoint) point;
      if (other == null) return false;
      return closeEnough(other.getLat(), as.getLat()) &&
             closeEnough(other.getLong(), as.getLong());
  }
}

Then use like this:

when(cityDefinitionRepository.findCitiesNearby(argThat(new IsSameLatLong(geoPoint)), eq(SOURCE), eq(2))).thenReturn(cityDefinitionsArrival);
when(cityDefinitionRepository.findCitiesNearby(argThat(new IsSameLatLong(geoPoint2)), eq(SOURCE), eq(2))).thenReturn(cityDefinitionsDeparture);
like image 121
weston Avatar answered Sep 28 '22 10:09

weston