是否有使用模拟作为数据流测试输入的好方法?

Is there a good way to use mocks as inputs to Dataflow tests?

我正在尝试测试 DoFn<KV<String, twitter4j.Status>, String> 实施,并提供测试数据作为输入。我正在探索的一种途径是使用 Mockito.mock 对象作为输入,因为有大量抽象方法可以实现。但是,在我的 DoFn 中调用模拟方法会改变对象,这样测试框架就会抱怨“值在输出后不能以任何方式发生变化”。

是否有其他方法可以完成我在这里尝试的工作?测试代码大致为:

 Status status = mock(Status.class, withSettings().serializable());
 when(status.getText()).thenReturn("bar");

 Pipeline p = TestPipeline.create();
 PCollection<String> strings = p
     .apply(Create.of(KV.of("foo", status)))
     .apply(MapElements.via(new TwitterUtils.StatusToJsonFn()));

 DataflowAssert.thatSingleton(strings).isEqualTo(...);

一种方法是创建一个不可变的包装器 class:

class StatusWrapper implements Serializable {
    private Status status;
    private String mockText;

    // Constructor for real usage
    StatusWrapper(Status status) { this.status = status; }

    // Constructor for mocks
    StatusWrapper() {}

    StatusWrapper withMockText(String text) {
        this.mockText = text; return this;
    }

    Status toStatus() {
        if (status != null) {
            return status;
        }
        Status status = mock(Status.class);
        when(status.getText()).thenReturn(mockText);
        return status;
    }
}

Pipeline p = TestPipeline.create();
PCollection<String> strings = p
    .apply(Create.of(new StatusWrapper().withMockText("bar")))
    .apply(MapElements.via(new TwitterUtils.StatusToJsonFn()));
DataflowAssert.thatSingleton(strings).isEqualTo(...);

StatusToJsonFn 将需要将 StatusWrapper 作为参数而不是 Status,并对其调用 toStatus() - 因为如果它采用 Status,它会遇到同样的问题。

在真实的管道中,可以这样使用:

PCollection<Status> realStatuses = ...;
PCollection<String> strings = realStatuses
    .apply(MapElements.via(StatusWrapper::new))
    .apply(MapElements.via(new TwitterUtils.StatusToJsonFn()));

查看 DoFnTester,它允许您通过提供输入数据并对结果断言来测试 DoFn:https://cloud.google.com/dataflow/pipelines/testing-your-pipeline