是否有使用模拟作为数据流测试输入的好方法?
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
我正在尝试测试 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