I'd rather instantiate Machine1 and feed it to some Builder,
Configurator or Adapter to get a StateMachine<> instance.
Spring State Mahcine supports annotation based configuration for instantiation (e.g. via Adapter) or a Builder - there's no other options.
Using @SpringBootTest(clasess = <YourEnumSMConfig>
definitely does not create a full application context:
@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();
}
}
Now I want to create Tests for it.
Testing with TestPlanBuilder:
There's a Testing support out of the box to test a spring state machine. It's called StateMachineTestPlan
. You can build StateMachineTestPlan
using StateMachineTestPlanBuilder
.
Access to these classes you can get from declaring the following dependency:
<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>
The detailed official documentation regarding testing is available here.
I would prefer not have an implicit
call to getBean("machine1")" via
StateMachineFactory.getStateMachine("machine1"), which would require
an application context.
Creating a SM via Builder does not require any Spring context.
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);
}
};
}