22. 测试流程

本章将教你如何测试流程。spring-doc.cadn.net.cn

22.1. 扩展摘要XmlFlow执行测试

要测试基于XML的流程定义的执行,你必须扩展摘要XmlFlow执行测试如下:spring-doc.cadn.net.cn

public class BookingFlowExecutionTests extends AbstractXmlFlowExecutionTests {

}

22.2. 指定通往测试流程的路径

至少,你必须覆盖getResource(FlowDefinitionResourceFactory)要返回你想测试的流程路径,具体如下:spring-doc.cadn.net.cn

@Override
protected FlowDefinitionResource getResource(FlowDefinitionResourceFactory resourceFactory) {
	return resourceFactory.createFileResource("src/main/webapp/WEB-INF/hotels/booking/booking.xml");
}

22.3. 记录流依赖关系

如果你的流程依赖外部托管服务,你也必须覆盖configureFlowBuilderContext(MockFlowBuilderContext)注册这些服务的简历或模拟服务,具体如下:spring-doc.cadn.net.cn

@Override
protected void configureFlowBuilderContext(MockFlowBuilderContext builderContext) {
	builderContext.registerBean("bookingService", new StubBookingService());
}

如果你的流从另一个流延伸,或者有状态延伸其他状态,你也必须覆盖getModelResources(FlowDefinitionResourceFactory)返回父流的路径如下:spring-doc.cadn.net.cn

@Override
protected FlowDefinitionResource[] getModelResources(FlowDefinitionResourceFactory resourceFactory) {
	return new FlowDefinitionResource[] {
		resourceFactory.createFileResource("src/main/webapp/WEB-INF/common/common.xml")
	};
}

22.4. 测试流程启动

以下示例展示了如何让你的第一个测试练习流程的启动:spring-doc.cadn.net.cn

public void testStartBookingFlow() {

	Booking booking = createTestBooking();

	MutableAttributeMap input = new LocalAttributeMap();
	input.put("hotelId", "1");
	MockExternalContext context = new MockExternalContext();
	context.setCurrentUser("keith");
	startFlow(input, context);

	assertCurrentStateEquals("enterBookingDetails");
	assertTrue(getRequiredFlowAttribute("booking") instanceof Booking);
}

断言通常会验证流是否处于你预期的状态。spring-doc.cadn.net.cn

22.5. 测试流程事件处理

你可以定义额外的测试来练习流事件处理行为。 你的目标应该是锻炼流程中的所有路径。 你可以利用方便的setCurrentState(String)跳转到你想开始测试的流程状态的方法如下:spring-doc.cadn.net.cn

public void testEnterBookingDetails_Proceed() {

	setCurrentState("enterBookingDetails");

	getFlowScope().put("booking", createTestBooking());

	MockExternalContext context = new MockExternalContext();
	context.setEventId("proceed");
	resumeFlow(context);

	assertCurrentStateEquals("reviewBooking");
}

22.6. 嘲讽子流

为了测试调用子流程,你可以注册一个子流程的模拟实现,该实现断言输入已正确传递,并返回适合你的测试场景的正确结果,具体如下:spring-doc.cadn.net.cn

public void testBookHotel() {

	setCurrentState("reviewHotel");

	Hotel hotel = new Hotel();
	hotel.setId(1L);
	hotel.setName("Jameson Inn");
	getFlowScope().put("hotel", hotel);

	getFlowDefinitionRegistry().registerFlowDefinition(createMockBookingSubflow());

	MockExternalContext context = new MockExternalContext();
	context.setEventId("book");
	resumeFlow(context);

	// verify flow ends on 'bookingConfirmed'
	assertFlowExecutionEnded();
	assertFlowExecutionOutcomeEquals("finish");
}

public Flow createMockBookingSubflow() {
	Flow mockBookingFlow = new Flow("booking");
	mockBookingFlow.setInputMapper(new Mapper() {
		public MappingResults map(Object source, Object target) {
			// assert that 1L was passed in as input
			assertEquals(1L, ((AttributeMap) source).get("hotelId"));
			return null;
		}
	});
	// immediately return the bookingConfirmed outcome so the caller can respond
	new EndState(mockBookingFlow, "bookingConfirmed");
	return mockBookingFlow;
}