我具有基于注释的状态计算机配置:
@Component @Scope(BeanDefinition.SCOPE_PROTOTYPE)
@EnableStateMachine(name = "machine1")
public class Machine1 extends
EnumStateMachineConfigurerAdapter<SimStates, SimEvents> {
@Override
public void configure(StateMachineStateConfigurer<SimStates, SimEvents> states) throws Exception {
states.withStates()
.initial(INIT)
.state(INIT)
.state(S1)
.state(FINISH)
.end(FINISH)
;
}
...
现在我想为它创建测试。我希望通过StateMachineFactory.getStateMachine("machine1")
对getBean("machine1")
的隐式调用,这需要应用程序上下文。
我宁愿实例化Machine1
并将其馈送到某些构建器,配置器或适配器以获取StateMachine<>
实例。
public class Machine1Test {
@Test
public void testMachine1() throws Exception {
final StateMachineConfigurer<SimStates, SimEvents> smc =
new Machine1();
final StateMachineBuilder.Builder<SimStates, SimEvents> builder =
StateMachineBuilder.builder();
// can I use the builder together with smc? Or something else?
StateMachine<SimStates,SimEvents> sm = ... // how?
}
}
更新:我更新了"没有完整的应用程序上下文"为"无隐式呼叫getBean("machine1")
"。问题还涉及了解Spring State Machine的所有工厂,适配器,配置和配置器。
我宁愿实例化Machine1并将其喂给一些建筑商, 配置器或适配器获取statemachine&lt;>实例。
春季状态Mahcine支持基于注释的实例化配置(例如,通过适配器)或构建器 - 没有其他选项。
通过适配器
SM使用@SpringBootTest(clasess = <YourEnumSMConfig>
绝对不会创建完整应用程序上下文:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = { Machine1.class})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class StateMachineTests {
@Autowired
private StateMachine<String, String> machine1;
@Test
public void testInitialState() throws Exception {
StatMachineTestPlan<SimState, SimEvent> plan = StateMachineTestPlanBuilder.<SimState, SimEvent>builder()
.defaultAwaitTime(2)
.stateMachine(machine1)
.step()
.expectStateChange(1)
.expectStateEntered(SimState.INITIAL)
.expectState(SimState.INITIAL)
.and()
.build()
plan.test();
}
}
现在我想为它创建测试。
使用TestplanBuilder测试:
可以开箱即用的测试支持来测试春季状态机。它称为StateMachineTestPlan
。您可以使用StateMachineTestPlanBuilder
构建StateMachineTestPlan
。
您可以从声明以下依赖项中获得这些类的访问:
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-test</artifactId>
<version>2.0.3.RELEASE</version> // change version to match yours
<scope>test</scope>
</dependency>
有关测试的详细官方文档,请参见此处。
通过建筑商SM
我宁愿没有隐式 致电GetBean(" Machine1")"通过 statemachinefactory.getstatemachine(" Machine1"),这需要 应用程序上下文。
通过构建器创建SM不需要任何春季上下文。
public class TestEventNotAccepted {
@Test
public void testEventNotAccepted() throws Exception {
StateMachine<String, String> machine = buildMachine();
StateMachineTestPlan<String, String> plan =
StateMachineTestPlanBuilder.<String, String>builder()
.defaultAwaitTime(2)
.stateMachine(machine)
.step()
.expectStates("SI")
.and()
.step()
.sendEvent("E2")
.and()
.build();
plan.test();
}
private StateMachine<String, String> buildMachine() throws Exception {
StateMachineBuilder.Builder<String, String> builder = StateMachineBuilder.builder();
builder.configureConfiguration()
.withConfiguration()
.taskExecutor(new SyncTaskExecutor())
.listener(customListener())
.autoStartup(true);
builder.configureStates()
.withStates()
.initial("SI")
.state("S1")
.state("S2");
builder.configureTransitions()
.withExternal()
.source("SI").target("S1")
.event("E1")
.action(c -> c.getExtendedState().getVariables().put("key1", "value1"))
.and()
.withExternal()
.source("S1").target("S2").event("E2");
return builder.build();
}
private StateMachineListener<String, String> customListener() {
return new StateMachineListenerAdapter<String, String>() {
@Override
public void eventNotAccepted(Message event) {
System.out.println("EVENT NOT ACCEPTED: " + event);
}
};
}
我没有找到与StateMachineBuilder.Builder<>
一起使用EnumStateMachineConfigurerAdapter
的明确方法,但是我已经使用了此方法:
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
@EnableStateMachine(name = "machine1")
public class Machine1 extends EnumStateMachineConfigurerAdapter<SimStates, SimEvents> {
@Override
public void configure(StateMachineStateConfigurer<SimStates, SimEvents> states) throws Exception {
configureStates(states);
}
@Override
public void configure(StateMachineTransitionConfigurer<SimStates, SimEvents> transitions) throws Exception {
configureTransitions(transitions);
}
public static void configureStates(StateMachineStateConfigurer<SimStates, SimEvents> states) throws Exception {
states.withStates()
.initial(INIT)
.state(INIT)
.state(S1)
.state(FINISH)
.end(FINISH);
}
public static void configureTransitions(StateMachineTransitionConfigurer<SimStates, SimEvents> states) throws Exception {
states.withTransitions()
// configure transitions
;
}
}
并在Statemachine测试中导入静态配置方法:
import static com.example.statemachine.Machine1.configureStates;
import static com.example.statemachine.Machine1.configureTransitions;
public class TestEventNotAccepted {
@Test
public void testEventNotAccepted() throws Exception {
StateMachine<SimStates, SimEvents> machine = buildMachine();
StateMachineTestPlan<SimStates, SimEvents> plan =
StateMachineTestPlanBuilder.<SimStates, SimEvents>builder()
.defaultAwaitTime(2)
.stateMachine(machine)
.step()
.expectStates(INIT)
.and()
// configure other test steps
.build();
plan.test();
}
private StateMachine<SimStates, SimEvents> buildMachine() throws Exception {
StateMachineBuilder.Builder<SimStates, SimEvents> builder = StateMachineBuilder.builder();
builder.configureConfiguration()
.withConfiguration()
.taskExecutor(new SyncTaskExecutor())
.listener(customListener())
.autoStartup(true);
configureStates(builder.configureStates());
configureTransitions(builder.configureTransitions());
return builder.build();
}
}
结果,我能够在不构建整个弹簧上下文而不使用@SpringBootTest
的情况下测试我的确切配置。