public FlowlessSystemPart<T> system(Consumer<T> systemReaction) { userPart.system(systemReaction); return new FlowlessSystemPart<>(flowlessStepCounter); } }
/** * Defines an "autonomous system reaction", meaning the system will react * without needing an event provided via {@link ModelRunner#reactTo(Object)}. * Instead, the model runner provides itself as an event to the system reaction. * * @param modelRunnerConsumer * the autonomous system reaction (that needs information from the model runner to work) * @return the created system part of this step */ StepSystemPart<ModelRunner> system(Consumer<ModelRunner> autonomousSystemReaction) { StepSystemPart<ModelRunner> systemPart = user(ModelRunner.class).system(autonomousSystemReaction); return systemPart; }
public Model buildWith(ModelBuilder modelBuilder) { Model model = modelBuilder.useCase("Feel Stuff") .basicFlow() .step("1").user(asksForPoem).system(feelStuffUseCaseRealization::writesSadPoem) .step("2").user(asksForPoem).system(feelStuffUseCaseRealization::writesHappyPoem) .step("3").user(asksForPoem).system(feelStuffUseCaseRealization::writesFunnyPoem) .build(); return model; } }
static Model model() { SaysHelloWorld saysHelloWorld = new SaysHelloWorld(); SaysHelloToUser saysHelloToUser = new SaysHelloToUser(); Model model = Model.builder().useCase("Say hello to world, then user") .basicFlow() .step("S1").user(ASKS_FOR_HELLO_WORLD).system(saysHelloWorld) .step("S2").user(ASKS_FOR_HELLO_TO_USER).system(saysHelloToUser) .build(); return model; }
public Model buildWith(ModelBuilder modelBuilder) { Model model = modelBuilder.useCase("Get greeted") .basicFlow() .step("S1").system(this::promptsUserToEnterFirstName) .step("S2").user(ENTERS_FIRST_NAME).system(this::savesFirstName) .step("S3").system(this::promptsUserToEnterAge) .step("S4").user(ENTERS_AGE).system(this::savesAge) .step("S5").system(this::greetsUserWithFirstNameAndAge) .build(); return model; }
@Test public void oneStepCanReactIfEventIsRight() { Model model = modelBuilder.useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()).build(); modelRunner.run(model); boolean canReact = modelRunner.canReactTo(entersText().getClass()); assertTrue(canReact); Set<Step> stepsThatCanReact = modelRunner.getStepsThatCanReactTo(entersText().getClass()); assertEquals(1, stepsThatCanReact.size()); assertEquals(CUSTOMER_ENTERS_TEXT, stepsThatCanReact.iterator().next().getName().toString()); }
@Test public void doesNotReactToEmptyEventList() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .build(); Optional<Step> latestStepRun = modelRunner.run(model).reactTo(new ArrayList<Object>()); assertFalse(latestStepRun.isPresent()); assertRecordedStepNames(new String[0]); }
@Test public void reactsToFirstStepAlternativeWhen() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(THIS_STEP_SHOULD_BE_SKIPPED).user(EntersText.class).system(throwsRuntimeException()) .step(THIS_STEP_SHOULD_BE_SKIPPED_AS_WELL).user(EntersText.class).system(throwsRuntimeException()) .flow(ALTERNATIVE_FLOW).condition(this::textIsNotAvailable) .step(CUSTOMER_ENTERS_ALTERNATIVE_TEXT).user(EntersText.class).system(displaysEnteredText()) .build(); modelRunner.run(model).reactTo(entersText()); assertRecordedStepNames(CUSTOMER_ENTERS_ALTERNATIVE_TEXT); }
@Test public void twoSequentialStepsReactToEventsOfDifferentType() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_NUMBER).user(EntersNumber.class).system(displaysEnteredNumber()) .build(); modelRunner.run(model); reactToAndAssertEvents(entersText(), entersNumber()); }
@Test public void cantReactIfEventIsWrong() { Model model = modelBuilder.useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .build(); modelRunner.run(model); boolean canReact = modelRunner.canReactTo(entersNumber().getClass()); assertFalse(canReact); }
@Test public void onlyStepWithTrueConditionReacts() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .flow("Alternative Flow: Skipped").condition(() -> false) .step(THIS_STEP_SHOULD_BE_SKIPPED).user(EntersText.class).system(throwsRuntimeException()) .build(); modelRunner.run(model).reactTo(entersText(), entersText()); assertRecordedStepNames(CUSTOMER_ENTERS_TEXT); }
@Test public void twoSequentialStepsReactWhenSeveralActorsContainRightActorAtFirstPosition() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT) .as(customer).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_TEXT_AGAIN) .as(customer, secondActor).user(EntersText.class).system(displaysEnteredText()) .build(); modelRunner.as(customer).run(model); reactToAndAssertEvents(entersText(), entersText()); }
@Test public void twoSequentialStepsReactWhenSeveralActorsContainRightActorAtSecondPosition() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT) .as(customer).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_TEXT_AGAIN) .as(secondActor, customer).user(EntersText.class).system(displaysEnteredText()) .build(); modelRunner.as(customer).run(model); reactToAndAssertEvents(entersText(), entersText()); }
@Test public void createsSingleStepThatHandlesUserCommandWithCondition() { UseCasePart useCasePart = modelBuilder.useCase(USE_CASE); useCasePart.basicFlow().condition(() -> textIsAvailable()) .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .build(); UseCase useCase = useCasePart.getUseCase(); assertTrue(useCase.getBasicFlow().getCondition().isPresent()); }
@Test public void onlyStepWithRightActorReacts() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT) .as(customer).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_TEXT_AGAIN) .as(secondActor).user(EntersText.class).system(throwsRuntimeException()) .build(); modelRunner.as(customer).run(model).reactTo(entersText(), entersText()); assertRecordedStepNames(CUSTOMER_ENTERS_TEXT); }
@Test public void oneStepInFlowReacts() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .build(); modelRunner.run(model); reactToAndAssertEvents(entersText()); }
@Test public void stepThasHasTrueConditionReactsEvenIfOtherStepWouldBePerformedBySystem() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .flow("Alternative Flow: Skipped").condition(() -> false) .step(THIS_STEP_SHOULD_BE_SKIPPED).system(() -> System.out.println("You should not see this!")) .build(); modelRunner.run(model).reactTo(entersText(), entersText()); assertRecordedStepNames(CUSTOMER_ENTERS_TEXT); }
@Test public void doesNotHandleExceptionIfNoExceptionOccurs() { Model model = modelBuilder.useCase(USE_CASE) .basicFlow() .step(SYSTEM_DISPLAYS_TEXT).system(displaysConstantText()) .flow(ALTERNATIVE_FLOW).after(SYSTEM_DISPLAYS_TEXT) .step(SYSTEM_HANDLES_EXCEPTION).on(ArrayIndexOutOfBoundsException.class).system(e -> {}) .build(); modelRunner.run(model); assertRecordedStepNames(SYSTEM_DISPLAYS_TEXT); }
@Test public void doesNotHandleExceptionIfSystemReactionDoesNotThrowException() { Model model = modelBuilder.useCase(USE_CASE) .basicFlow() .step(SYSTEM_DISPLAYS_TEXT).system(displaysConstantText()) .flow(ALTERNATIVE_FLOW).after(SYSTEM_DISPLAYS_TEXT) .step(SYSTEM_HANDLES_EXCEPTION).on(ArrayIndexOutOfBoundsException.class).system(e -> {}) .build(); modelRunner.run(model); assertRecordedStepNames(SYSTEM_DISPLAYS_TEXT); }
@Test public void handlesExceptionAfterSpecificStep() { Model model = modelBuilder.useCase(USE_CASE) .basicFlow() .step(SYSTEM_THROWS_EXCEPTION).system(throwsArrayIndexOutOfBoundsException()) .flow(ALTERNATIVE_FLOW).after(SYSTEM_THROWS_EXCEPTION) .step(SYSTEM_HANDLES_EXCEPTION).on(ArrayIndexOutOfBoundsException.class).system(e -> {}) .build(); modelRunner.run(model); assertEquals(SYSTEM_HANDLES_EXCEPTION, latestStepName()); }