如何从Statemachineconfigurer创建statemachine



我具有基于注释的状态计算机配置:

@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的情况下测试我的确切配置。

相关内容

  • 没有找到相关文章

最新更新