在 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();
我正在为 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();