Add test support for intermediate state changes
- Adding expectStateEntered and expectStateExited methods for testing state enter/exit in a given order. This gives on option to expect i.e. states via anonymous transitions. - Fixes #154
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
:core-jdbc-JdbcTemplate: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/jdbc.html#jdbc-JdbcTemplate
|
||||
:sm-statecontext: http://docs.spring.io/spring-statemachine/docs/{spring-statemachine-version}/api/org/springframework/statemachine/StateContext.html
|
||||
:sm-statecontext-stage: http://docs.spring.io/spring-statemachine/docs/{spring-statemachine-version}/api/org/springframework/statemachine/StateContext.Stage.html
|
||||
:sm-statemachinetestplanbuilder-statemachinetestplanstepbuilder: http://docs.spring.io/spring-statemachine/docs/{spring-statemachine-version}/api/org/springframework/statemachine/test/StateMachineTestPlanBuilder.StateMachineTestPlanStepBuilder.html
|
||||
:spring-security-site: http://projects.spring.io/spring-security
|
||||
|
||||
= Spring Statemachine - Reference Documentation
|
||||
|
||||
@@ -1532,3 +1532,9 @@ These utilities are also used within a framework to test distributed
|
||||
state machine features and multiple machines can be added to a plan.
|
||||
If multiple machines are added then it is also possible to choose if
|
||||
event is sent to particular, random or all machines.
|
||||
|
||||
[TIP]
|
||||
====
|
||||
All possible options for expected are documented in javadocs
|
||||
{sm-statemachinetestplanbuilder-statemachinetestplanstepbuilder}[_StateMachineTestPlanStepBuilder_].
|
||||
====
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
*/
|
||||
package org.springframework.statemachine.test;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -36,6 +37,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.test.StateMachineTestPlanBuilder.StateMachineTestPlanStep;
|
||||
import org.springframework.statemachine.test.support.LatchStateMachineListener;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -229,6 +231,26 @@ public class StateMachineTestPlan<S, E> {
|
||||
}
|
||||
}
|
||||
|
||||
if (!step.expectStatesEntrered.isEmpty()) {
|
||||
for (LatchStateMachineListener<S, E> listener : listeners.values()) {
|
||||
Collection<S> states = new ArrayList<S>();
|
||||
for (State<S, E> s : listener.getStateEntered()) {
|
||||
states.add(s.getId());
|
||||
}
|
||||
assertThat(step.expectStatesEntrered, contains(states.toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!step.expectStatesExited.isEmpty()) {
|
||||
for (LatchStateMachineListener<S, E> listener : listeners.values()) {
|
||||
Collection<S> states = new ArrayList<S>();
|
||||
for (State<S, E> s : listener.getStateExited()) {
|
||||
states.add(s.getId());
|
||||
}
|
||||
assertThat(step.expectStatesExited, contains(states.toArray()));
|
||||
}
|
||||
}
|
||||
|
||||
if (step.expectExtendedStateChanged != null) {
|
||||
for (LatchStateMachineListener<S, E> listener : listeners.values()) {
|
||||
assertThat(listener.getExtendedStateChangedLatch().await(defaultAwaitTime, TimeUnit.SECONDS), is(true));
|
||||
|
||||
@@ -116,6 +116,8 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
boolean sendEventToAll = false;
|
||||
boolean sendEventParallel = false;
|
||||
final Collection<S> expectStates = new ArrayList<S>();
|
||||
final Collection<S> expectStatesEntrered = new ArrayList<S>();
|
||||
final Collection<S> expectStatesExited = new ArrayList<S>();
|
||||
Integer expectStateChanged;
|
||||
Integer expectStateEntered;
|
||||
Integer expectStateExited;
|
||||
@@ -295,6 +297,30 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect states entered in order given.
|
||||
*
|
||||
* @param states the states entered
|
||||
* @return the state machine test plan step builder
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public StateMachineTestPlanStepBuilder expectStateEntered(S... states) {
|
||||
this.expectStatesEntrered.addAll(Arrays.asList(states));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect states exited in order given.
|
||||
*
|
||||
* @param states the states exited
|
||||
* @return the state machine test plan step builder
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public StateMachineTestPlanStepBuilder expectStateExited(S... states) {
|
||||
this.expectStatesExited.addAll(Arrays.asList(states));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect state enter happening {@code count} times.
|
||||
*
|
||||
@@ -433,7 +459,7 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
sendEventParallel, expectStates, expectStateChanged, expectStateEntered, expectStateExited,
|
||||
expectEventNotAccepted, expectTransition, expectTransitionStarted, expectTransitionEnded,
|
||||
expectStateMachineStarted, expectStateMachineStopped, expectVariableKeys, expectVariables,
|
||||
expectExtendedStateChanged));
|
||||
expectExtendedStateChanged, expectStatesEntrered, expectStatesExited));
|
||||
return StateMachineTestPlanBuilder.this;
|
||||
}
|
||||
|
||||
@@ -446,6 +472,8 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
boolean sendEventToAll = false;
|
||||
boolean sendEventParallel = false;
|
||||
final Collection<S> expectStates;
|
||||
final Collection<S> expectStatesEntrered;
|
||||
final Collection<S> expectStatesExited;
|
||||
Integer expectStateChanged;
|
||||
Integer expectStateEntered;
|
||||
Integer expectStateExited;
|
||||
@@ -465,7 +493,7 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
Integer expectEventNotAccepted, Integer expectTransition, Integer expectTransitionStarted,
|
||||
Integer expectTransitionEnded, Integer expectStateMachineStarted, Integer expectStateMachineStopped,
|
||||
Collection<Object> expectVariableKeys, Map<Object, Object> expectVariables,
|
||||
Integer expectExtendedStateChanged) {
|
||||
Integer expectExtendedStateChanged, Collection<S> expectStatesEntrered, Collection<S> expectStatesExited) {
|
||||
this.sendEvent = sendEvent;
|
||||
this.sendMessage = sendMessage;
|
||||
this.sendEventMachineId = sendEventMachineId;
|
||||
@@ -484,6 +512,8 @@ public class StateMachineTestPlanBuilder<S, E> {
|
||||
this.expectVariableKeys = expectVariableKeys;
|
||||
this.expectVariables = expectVariables;
|
||||
this.expectExtendedStateChanged = expectExtendedStateChanged;
|
||||
this.expectStatesEntrered = expectStatesEntrered;
|
||||
this.expectStatesExited = expectStatesExited;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,6 +87,24 @@ public class StateMachineTestingTests extends AbstractStateMachineTests {
|
||||
plan.test();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testIntermediate() throws Exception {
|
||||
registerAndRefresh(Config4.class);
|
||||
StateMachine<String, String> machine = context.getBean(StateMachine.class);
|
||||
|
||||
StateMachineTestPlan<String, String> plan =
|
||||
StateMachineTestPlanBuilder.<String, String>builder()
|
||||
.stateMachine(machine)
|
||||
.step().expectStateMachineStarted(1).and()
|
||||
.step().expectState("SI").and()
|
||||
.step().sendEvent("E1").expectStateChanged(1).expectState("S1").and()
|
||||
.step().sendEvent("E2").expectStateChanged(2).expectStateEntered("S2", "S3").expectStateExited("S1", "S2").expectState("S3").and()
|
||||
.build();
|
||||
|
||||
plan.test();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotationConfigApplicationContext buildContext() {
|
||||
return new AnnotationConfigApplicationContext();
|
||||
@@ -194,4 +212,38 @@ public class StateMachineTestingTests extends AbstractStateMachineTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config4 extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.initial("SI")
|
||||
.state("S1")
|
||||
.state("S2")
|
||||
.state("S3");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source("SI")
|
||||
.target("S1")
|
||||
.event("E1")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S1")
|
||||
.target("S2")
|
||||
.event("E2")
|
||||
.and()
|
||||
.withExternal()
|
||||
.source("S2")
|
||||
.target("S3");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user