0

I want to unit test a repository which depends on LocationLiveData class:

public class LocationLiveData extends LiveData<LocationData> {
    private Context mContext;

    private LocationCallback locationCallback = new LocationCallback(){
        @Override
        public void onLocationResult(LocationResult locationResult) {
            ...
            setValue(locationData);
        }
    };

    @Inject
    public LocationLiveData(Context context) {
        mContext = context;
        ...     
    }
    ...
}

How can I make the mock act like liveData which emits a LocationData object after I called setValue(someLocationDataInstance)?

@RunWith(JUnit4.class)
public class LocationRepoImplTest {
    @Rule
    public InstantTaskExecutorRule instantExecutorRule = new InstantTaskExecutorRule();
    private LocationRepo mLocationRepo;
    private LocationLiveData mlocationLiveData;


    @Before
    public void setUp() throws Exception {
        mlocationLiveData = mock(LocationLiveData.class);//(LocationLiveData) new MutableLiveData<LocationData>();
        mLocationRepo = new LocationRepoImpl(mlocationLiveData);
    }

    @Test
    public void getUserPosition() throws Exception {
        LiveData<LatLng> result =  mLocationRepo.getUserPosition();
        Observer observer = mock(Observer.class);
        result.observeForever(observer);
        //how can I setValue for mLocationLiveData here?
        //e.g this way: mLocationLiveData.setValue(new LocationData(TestUtil.posUser, (float) 10.0));
        assertThat(result.getValue(), is(TestUtil.posUser));
    }
}

Update 1: I want to test following repository:

public class LocationRepoImpl implements LocationRepo {

private LocationLiveData mLocationLiveData;

@Inject
public LocationRepoImpl(LocationLiveData locationLiveData) {
    mLocationLiveData = locationLiveData;
}

@Override
public LiveData<LatLng> getUserPosition() {
    return Transformations.map(mLocationLiveData, LocationData::getLatLng);
}

}

Sagar
  • 23,903
  • 4
  • 62
  • 62
piveloper
  • 175
  • 2
  • 9
  • Your assert statement claims that the getValue, a `LocationData` is `TestUtil.posUser`. I'm not sure why you'd need to assert that a mock is returning an object you explicitly tell it to do so. When you mock a repository, you should only be scripting its outputs, not it its inputs. Unless `setValue` returns anything, you don't need to handle anything regarding `setValue` in this case. You can call it and it'll do, as expected of a mock, nothing. – Compass Nov 07 '17 at 17:47
  • I don't want to mock the repository. I want to mock the locationLiveData which gets into the constructor of the repository under test. My code was a bit misleading. I modified it and added the `LocationRepoImpl`. – piveloper Nov 07 '17 at 18:10
  • So, let me make sure I am understanding you correctly. You have a `mock mLocationLiveData` and have it do something when `setValue` is called. Is `setValue` a void? If so, there's really not much you can do with it. If you want `getValue` to provide new different values each time, you can use something like thenAnswer https://stackoverflow.com/questions/8088179/using-mockito-with-multiple-calls-to-the-same-method-with-the-same-arguments Using the mocked `setValue` to actually set the value is more shoehorning unmocked functionality into the mock. – Compass Nov 07 '17 at 18:21
  • setValue comes from the liveData class from google. I set the generic T as LocationData. https://developer.android.com/reference/android/arch/lifecycle/LiveData.html – piveloper Nov 07 '17 at 18:27
  • Thanks for the javadoc. I see that it's a void, so in most cases, you'd only want to verify that it was called in your code. You can spy for that. – Compass Nov 07 '17 at 18:29
  • Thanks for the spy proposal. In principle it is a good idea but it does not help me here for two reasons: First `LocationLiveData` has android dependencies in it which cannot be instantiated in a unit test. Second setValue() is protected such that in can only be called within the class and I don't want to modify code for a testing purposes. – piveloper Nov 07 '17 at 23:12

0 Answers0