单元测试
通常,我们假设Flink
在用户定义的函数(Function
)之外都能够产生正确的结果。因此,推荐大家尽可能多的测试包含主要业务逻辑的函数(Function
)类。
比如,如果有人实现了下面的ReduceFunction
:
public class SumReduce implements ReduceFunction<Long> {
@Override
public Long reduce(Long value1, Long value2) throws Exception {
return value1 + value2;
}
}
复制代码
你可以很方便的使用自己喜欢的测试框架测试这个类。
public class SumReduceTest {
@Test
public void testSum() throws Exception {
// instantiate your function
SumReduce sumReduce = new SumReduce();
// call the methods that you have implemented
assertEquals(42L, sumReduce.reduce(40L, 2L));
}
}
复制代码
集成测试
为了端到端测试Flink
流管道(streaming pipeline
),你也可以写一个在本地小型集群上执行的集成测试。
为此要首先添加依赖flink-test-utils
:
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-test-utils_2.11</artifactId>
<version>1.7.0</version>
</dependency>
复制代码
举例来说,你想测试下面的MapFunction
:
public class MultiplyByTwo implements MapFunction<Long, Long> {
@Override
public Long map(Long value) throws Exception {
return value * 2;
}
}
复制代码
你可以写如下的集成测试:
public class ExampleIntegrationTest extends AbstractTestBase {
@Test
public void testMultiply() throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// configure your test environment
env.setParallelism(1);
// values are collected in a static variable
CollectSink.values.clear();
// create a stream of custom elements and apply transformations
env.fromElements(1L, 21L, 22L)
.map(new MultiplyByTwo())
.addSink(new CollectSink());
// execute
env.execute();
// verify your results
assertEquals(Lists.newArrayList(2L, 42L, 44L), CollectSink.values);
}
// create a testing sink
private static class CollectSink implements SinkFunction<Long> {
// must be static
public static final List<Long> values = new ArrayList<>();
@Override
public synchronized void invoke(Long value) throws Exception {
values.add(value);
}
}
}
复制代码
在CollectSink
里使用静态变量是因为Flink
在将其分发到集群上之前会序列化所有的算子(operators
)。使用静态变量与本地Flink
小型集群实例化的算子(operators
)通信是这个问题的一种解决方案。或者,你也可以让测试sink
把数据写到一个临时目录下的文件里。你也可以实现自定义的source
来发出水印(wartermark
)。
测试checkpointing
和状态处理
状态测试的一种方式是在集成测试里打开checkpointing
。
你可以在测试中配置StreamExecutionEnvironment
来做到这一点。
env.enableCheckpointing(500);
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3, 100));
复制代码
例如,向Flink
应用程序添加一个身份映射器算子,该算子将每1000毫秒抛出一次异常。但是,由于动作之间存在时间依赖关系,因此编写此类测试可能会非常棘手。
另一种方法是使用flink-streaming-java
模块下的Flink
内部测试实用程序AbstractStreamOperatorTestHarness
编写单元测试。
有关如何执行此操作的示例,请在flink-streaming-java
模块中查看org.apache.flink.streaming.runtime.operators.windowing.WindowOperatorTest
请注意,AbstractStreamOperatorTestHarness
当前不是公共API的一部分,可能会有所变化。