如何将通用 class 与 Mockito.when 一起使用

How to use generic class with Mockito.when

我正在尝试使用参数化测试,我想在以下场景中使用 Mockito.when()。除了测试之外,我无法修改任何代码。我已经对目前导致编译错误的行发表了评论。我很难用语言表达它,但基本上我希望能够模拟该方法,而无需在编译期间访问确切的类型。

测试class:

import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Map;

import static com.example.demo.Type.A;
import static com.example.demo.Type.B;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class MyTest {

    private static final Map<Type, Class<? extends MyStuff>> classByType = Map.of(A, StuffA.class, B, StuffB.class);

    @InjectMocks
    private Handler handler;

    @Mock
    private Converter converter;

    @Mock
    private Sender sender;

    @Captor
    private ArgumentCaptor<Thing> thingArgumentCaptor;

    @ParameterizedTest
    @EnumSource(value = Type.class)
    void testHandle(Type type) {
        MyStuff myStuff = mock(classByType.get(type));
        Thing thing = mock(Thing.class);
        when(myStuff.getType()).thenReturn(type);
        when(converter.convert(classByType.get(type).cast(type))).thenReturn(thing); // This line is causing the compile error

        handler.handle(myStuff);

        verify(sender).send(thingArgumentCaptor.capture());
        assertThat(thingArgumentCaptor.getValue()).isEqualTo(thing);
    }


}

Class 测试中:

public class Handler {

    private final Converter converter;
    private final Sender sender;

    public Handler(Converter converter, Sender sender) {
        this.converter = converter;
        this.sender = sender;
    }

    public void handle(MyStuff myStuff) {
        Thing thing;
        switch (myStuff.getType()) {
            case A:
                thing = converter.convert((StuffA) myStuff);
                break;
            case B:
                thing = converter.convert((StuffB) myStuff);
                break;
            default:
                throw new RuntimeException();
        }
        sender.send(thing);

    }
}

域对象:

public abstract class MyStuff {
    public abstract Type getType();
}

转换器:

public interface Converter {
    Thing convert(StuffA myType);

    Thing convert(StuffB myType);
}

发件人:

public interface Sender {
    void send(Thing thing);
}

类型:

public enum Type {
    A, B
}

有没有不用写两个单独的测试方法就可以解决这个问题的方法?

您可以使用反射来调用适当的方法。尝试用以下两行替换编译错误的行:

       ​Method method = Converter.class.getMethod("convert", classByType.get(type));
       ​when(method.invoke(converter, eq(myStuff))).thenReturn(thing);

如果在编译时不知道方法参数的类型,那么反射是唯一的方法。