3

I have some logic quite similar to this, where i have unit and different fields that can be updated during request.

public class Unit {
    int x;
    int y;

    public void updateX(int x) {
        this.x += x;
    }

    public void updateY(int y) {
        this.y += y;
    }
}

public class UpdateUnitService{
    public Unit update(int delta, BiConsumer<Unit, Integer> updater){
        Unit unit = getUnit(); //method that can`t be mocked
        updater.accept(unit, delta);
        // some save logic

        return unit;
    }
}

public class ActionHandler{
    private UpdateUnitService service;

    public Unit update(Request request){
        if (request.someFlag()){
            return service.update(request.data, Unit::updateX);
        }else {
            return service.update(request.data, Unit::updateY);
        }
    }
}

And I need write some test for checking what function was called. Something like this.

verify(service).update(10, Unit::updateX);
verify(service).update(10, Unit::updateY);

How to write test like this using ArgumentCaptor or something else?

ETO
  • 6,970
  • 1
  • 20
  • 37
IgorGudkov
  • 143
  • 1
  • 10
  • 2
    You should test whether the operation does the right thing, which is whether the `Unit` contains the right values afterwards. How it does it, e.g. by calling a particular method via method reference, is irrelevant. – Holger Jan 22 '19 at 17:11

1 Answers1

1

There is no way (in current implementation of Java) to compare two lambdas and/or method references. For more details read this post.

What you could do (in case getUnit() is unmockable) is to check whether the two method references do the same thing when invoked. But you can't verify any unknown side effects.

public void verifyUpdateTheSameField(Integer value, BiConsumer<Unit, Integer> updater1, BiConsumer<Unit, Integer> updater2) {
    Unit unit1 = // initialize a unit
    Unit unit2 = // initialize to be equal to unit1

    actual.accept(unit1, value);
    expected.accept(unit2, value);

    assertThat(unit1).isEqualTo(unit2);
}

And then:

ArgumentCaptor<Integer> valueCaptor = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<BiConsumer<Unit, Integer>> updaterCaptor = ArgumentCaptor.forClass(BiConsumer.class);

verify(handler.service, times(1)).update(valueCaptor.capture(), updaterCaptor.capture());

verifyUpdateTheSameFields(valueCaptor.getValue(), updaterCaptor.getValue(), Unit::updateX);

Note: This approach will work only if Unit overrides equals.

ETO
  • 6,970
  • 1
  • 20
  • 37