在 Apache Flink 1.4 中模拟 ListState

Mocking a ListState in Apache Flink 1.4

我正在为 Apache Flink 1.4 中的 processElement 函数编写一些测试代码:

public class ProcessFunctionClass {

    public void processElement(Tuple2<String, String> tuple2,  Context context, Collector<Tuple2<String, String>> collector) {

        // if the state is empty, start a timer
        if (listState.get().iterator().hasNext() == false)
            context.timerService().registerEventTimeTimer(1000);

        listState.add("someStringToBeStored");

        // ...
    }

}
public class ProcessFunctionClassTest {

    private ProcessFunctionClass processFunctionClass;

    @Mock
    private ListState<String> listState;

    @Before
    public void setUp() throws Exception {
        processFunctionClass = new ProcessFunctionClass();
    }

    @Test
    public void testProcessElement() {

        ListState mockListState = mock(ListState.class);
        Iterable mockIterable = mock(Iterable.class);
        Iterator mockIterator = mock(Iterator.class);
        MockitoAnnotations.initMocks(this);

        when(tDPListState.get()).thenReturn(mockIterable);
        when(tDPListState.get().iterator()).thenReturn(mockIterator);
        when(tDPListState.get().iterator().hasNext()).thenReturn(false);

        processFunctionClass.processElement(tuple2, context, collector);

        // verify(...)
    }
}

当我使用 IDE 进行调试时,就在我进入 processElement() 方法之前,listState 不是 null 并且似乎已成功模拟,但是我一到达 listState.get().iterator().hasNext()listState 就是 null,我得到一个 NullPointerException。我在这里做错了什么?

ProcessFunctionClass 中你有一个私有的 listState 变量。 在您的测试中,您创建了一个完全不相关的 mockListState 变量并对其设置了一些期望值。

为了使测试生效,您必须提供一种方法(构造函数或 setter)将 ProcessFunctionClass.listState 设置为所需值(您的模拟列表状态)

最重要的是,MockitoAnnotations.initMocks(this); 在您的示例中似乎什么也没做:您没有向我们展示任何用 @Mock@InjectMocks

注释的字段

更新

您误用了 @Mock 注释。 你应该把它放在测试 class 中,而不是放在测试中 class 中。 当放置在测试 class 中时,在调用 initMocks 之后,将使用适当类型的 mock 初始化字段。

您应该改为:

  • 删除 MockitoAnnotations.initMocks(this);,您正在手动创建所有模拟。
  • ProcessFunctionClass
  • 中添加构造函数
public ProcessFunctionClass(ListState<String> listState) {
    this.listState = listState
}
  • 在你的测试中使用这个构造函数
var mockListState = mock(ListState.class);
var processFunctionClass = new ProcessFunctionClass();