diff --git a/docs/src/reference/asciidoc/sm.adoc b/docs/src/reference/asciidoc/sm.adoc index 99ee33a7..c8e205a9 100644 --- a/docs/src/reference/asciidoc/sm.adoc +++ b/docs/src/reference/asciidoc/sm.adoc @@ -2066,6 +2066,13 @@ 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. +Above testing example uses hamcrest imports: + +[source,java,indent=0] +---- +include::samples/DocsTestSampleTests.java[tags=snippetC] +---- + [TIP] ==== All possible options for expected are documented in javadocs diff --git a/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlan.java b/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlan.java index 7c9a3c80..da35a351 100644 --- a/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlan.java +++ b/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlan.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hamcrest.Matcher; +import org.hamcrest.collection.IsMapContaining; import org.springframework.messaging.Message; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.state.State; @@ -262,8 +263,18 @@ public class StateMachineTestPlan { for (StateMachine stateMachine : stateMachines.values()) { Map variables = stateMachine.getExtendedState().getVariables(); for (Object key : step.expectVariableKeys) { - assertThat("Key " + key + " doesn't exist in extended state variables", - variables.containsKey(key), is(true)); + org.hamcrest.MatcherAssert.assertThat( + "Key [" + key + "] doesn't exist in extended state variables", variables, + IsMapContaining.hasKey(key)); + } + } + } + + if (!step.expectVariableMatchers.isEmpty()) { + for (StateMachine stateMachine : stateMachines.values()) { + Map variables = stateMachine.getExtendedState().getVariables(); + for (Matcher> matcher : step.expectVariableMatchers) { + org.hamcrest.MatcherAssert.assertThat(variables, matcher); } } } @@ -272,10 +283,10 @@ public class StateMachineTestPlan { for (StateMachine stateMachine : stateMachines.values()) { Map variables = stateMachine.getExtendedState().getVariables(); for (Entry entry : step.expectVariables.entrySet()) { - assertThat("Key " + entry.getKey() + " doesn't exist in extended state variables", - variables.containsKey(entry.getKey()), is(true)); - assertThat("Variable " + entry.getKey() + " doesn't match in extended state variables", - variables.get(entry.getKey()), is(entry.getValue())); + org.hamcrest.MatcherAssert.assertThat( + "Entry with key=[" + entry.getKey() + "] value=[" + entry.getValue() + + "] doesn't exist in extended state variables", + variables, IsMapContaining.hasEntry(entry.getKey(), entry.getValue())); } } } diff --git a/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlanBuilder.java b/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlanBuilder.java index 2aa8449c..4ef42f18 100644 --- a/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlanBuilder.java +++ b/spring-statemachine-test/src/main/java/org/springframework/statemachine/test/StateMachineTestPlanBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.hamcrest.Matcher; import org.springframework.messaging.Message; import org.springframework.statemachine.StateMachine; @@ -129,9 +130,9 @@ public class StateMachineTestPlanBuilder { Integer expectStateMachineStopped; Integer expectExtendedStateChanged; final Collection expectVariableKeys = new ArrayList(); + final Collection>> expectVariableMatchers = new ArrayList<>(); final Map expectVariables = new HashMap(); - /** * Expect a state {@code S}. * @@ -249,6 +250,7 @@ public class StateMachineTestPlanBuilder { * by {@code machineId}. Multiple events can be defined which are then * send in defined order. * + * * @param event the event * @param machineId the machine identifier for sending event * @return the state machine test plan step builder @@ -270,6 +272,17 @@ public class StateMachineTestPlanBuilder { return this; } + /** + * Expect variable map with hamcrest {@link Matcher}. + * + * @param matcher the matcher + * @return the state machine test plan step builder + */ + public StateMachineTestPlanStepBuilder expectVariableWith(Matcher> matcher) { + this.expectVariableMatchers.add(matcher); + return this; + } + /** * Expect variable to exist in extended state variables and match * with the value. @@ -458,8 +471,9 @@ public class StateMachineTestPlanBuilder { steps.add(new StateMachineTestPlanStep(sendEvent, sendMessage, sendEventMachineId, sendEventToAll, sendEventParallel, expectStates, expectStateChanged, expectStateEntered, expectStateExited, expectEventNotAccepted, expectTransition, expectTransitionStarted, expectTransitionEnded, - expectStateMachineStarted, expectStateMachineStopped, expectVariableKeys, expectVariables, - expectExtendedStateChanged, expectStatesEntrered, expectStatesExited)); + expectStateMachineStarted, expectStateMachineStopped, expectVariableKeys, + expectVariableMatchers, expectVariables, expectExtendedStateChanged, + expectStatesEntrered, expectStatesExited)); return StateMachineTestPlanBuilder.this; } @@ -485,6 +499,7 @@ public class StateMachineTestPlanBuilder { Integer expectStateMachineStopped; Integer expectExtendedStateChanged; final Collection expectVariableKeys; + final Collection>> expectVariableMatchers; final Map expectVariables; public StateMachineTestPlanStep(List sendEvent, List> sendMessage, Object sendEventMachineId, @@ -492,8 +507,10 @@ public class StateMachineTestPlanBuilder { Integer expectStateChanged, Integer expectStateEntered, Integer expectStateExited, Integer expectEventNotAccepted, Integer expectTransition, Integer expectTransitionStarted, Integer expectTransitionEnded, Integer expectStateMachineStarted, Integer expectStateMachineStopped, - Collection expectVariableKeys, Map expectVariables, - Integer expectExtendedStateChanged, Collection expectStatesEntrered, Collection expectStatesExited) { + Collection expectVariableKeys, Collection>> expectVariableMatchers, + Map expectVariables, + Integer expectExtendedStateChanged, Collection expectStatesEntrered, + Collection expectStatesExited) { this.sendEvent = sendEvent; this.sendMessage = sendMessage; this.sendEventMachineId = sendEventMachineId; @@ -510,6 +527,7 @@ public class StateMachineTestPlanBuilder { this.expectStateMachineStarted = expectStateMachineStarted; this.expectStateMachineStopped = expectStateMachineStopped; this.expectVariableKeys = expectVariableKeys; + this.expectVariableMatchers = expectVariableMatchers; this.expectVariables = expectVariables; this.expectExtendedStateChanged = expectExtendedStateChanged; this.expectStatesEntrered = expectStatesEntrered; diff --git a/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/StateMachineTestingTests.java b/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/StateMachineTestingTests.java index b8028121..570842ea 100644 --- a/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/StateMachineTestingTests.java +++ b/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/StateMachineTestingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,9 @@ */ package org.springframework.statemachine.test; +import static org.hamcrest.CoreMatchers.not; + +import org.hamcrest.collection.IsMapContaining; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -105,6 +108,48 @@ public class StateMachineTestingTests extends AbstractStateMachineTests { plan.test(); } + @SuppressWarnings("unchecked") + @Test + public void testVariables() throws Exception { + registerAndRefresh(Config5.class); + StateMachine machine = context.getBean(StateMachine.class); + + StateMachineTestPlan plan = + StateMachineTestPlanBuilder.builder() + .stateMachine(machine) + .step().expectStateMachineStarted(1).and() + .step().expectState("SI").and() + .step() + .sendEvent("E1") + .expectStateChanged(1) + .expectState("S1") + .expectVariable("V1Key") + .expectVariable("V1Key", "V1Value") + .expectVariableWith(IsMapContaining.hasKey("V1Key")) + .expectVariableWith(IsMapContaining.hasValue("V1Value")) + .expectVariableWith(IsMapContaining.hasEntry("V1Key", "V1Value")) + .expectVariableWith(not(IsMapContaining.hasKey("V2Key"))) + .and() + .step() + .sendEvent("E2") + .expectStateChanged(1) + .expectState("S2") + .expectVariable("V1Key") + .expectVariable("V1Key", "V1Value") + .expectVariable("V2Key") + .expectVariable("V2Key", "V2Value") + .expectVariableWith(IsMapContaining.hasKey("V1Key")) + .expectVariableWith(IsMapContaining.hasValue("V1Value")) + .expectVariableWith(IsMapContaining.hasEntry("V1Key", "V1Value")) + .expectVariableWith(IsMapContaining.hasKey("V2Key")) + .expectVariableWith(IsMapContaining.hasValue("V2Value")) + .expectVariableWith(IsMapContaining.hasEntry("V2Key", "V2Value")) + .and() + .build(); + + plan.test(); + } + @Override protected AnnotationConfigApplicationContext buildContext() { return new AnnotationConfigApplicationContext(); @@ -246,4 +291,37 @@ public class StateMachineTestingTests extends AbstractStateMachineTests { } + @Configuration + @EnableStateMachine + static class Config5 extends StateMachineConfigurerAdapter { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial("SI") + .state("S1") + .state("S2"); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source("SI") + .target("S1") + .event("E1") + .action(c -> { + c.getExtendedState().getVariables().put("V1Key", "V1Value"); + }) + .and() + .withExternal() + .source("S1") + .target("S2") + .event("E2") + .action(c -> { + c.getExtendedState().getVariables().put("V2Key", "V2Value"); + }); + } + } } diff --git a/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/docs/DocsTestSampleTests.java b/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/docs/DocsTestSampleTests.java index 33945517..9bdd5a06 100644 --- a/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/docs/DocsTestSampleTests.java +++ b/spring-statemachine-test/src/test/java/org/springframework/statemachine/test/docs/DocsTestSampleTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,13 @@ */ package org.springframework.statemachine.test.docs; +//tag::snippetC[] +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.collection.IsMapContaining.hasKey; +import static org.hamcrest.collection.IsMapContaining.hasValue; +import static org.hamcrest.collection.IsMapContaining.hasEntry; +//end::snippetC[] + import org.junit.Test; import org.springframework.core.task.SyncTaskExecutor; import org.springframework.statemachine.StateMachine; @@ -39,6 +46,12 @@ public class DocsTestSampleTests { .sendEvent("E1") .expectStateChanged(1) .expectStates("S1") + .expectVariable("key1") + .expectVariable("key1", "value1") + .expectVariableWith(hasKey("key1")) + .expectVariableWith(hasValue("value1")) + .expectVariableWith(hasEntry("key1", "value1")) + .expectVariableWith(not(hasKey("key2"))) .and() .build(); plan.test(); @@ -62,7 +75,10 @@ public class DocsTestSampleTests { builder.configureTransitions() .withExternal() .source("SI").target("S1") - .event("E1"); + .event("E1") + .action(c -> { + c.getExtendedState().getVariables().put("key1", "value1"); + }); return builder.build(); }