public Model buildWith(ModelBuilder modelBuilder) { Model model = modelBuilder.useCase("Get greeted") .basicFlow() .step("S1").system(this::greetsUser) .build(); return model; }
/** * Creates a new flow in the current use case. * * @param flowName * the name of the flow to be created. * @return the newly created flow part * @throws ElementAlreadyInModel * if a flow with the specified name already exists in the use case */ public FlowPart flow(String flowName) { Objects.requireNonNull(flowName); FlowPart useCaseFlowPart = stepPart.getUseCasePart().flow(flowName); return useCaseFlowPart; }
public Model build() { return UseCasePart.this.build(); }
@Test public void createsSingleStepWithNoPreviousStep() { UseCasePart useCasePart = modelBuilder.useCase(USE_CASE); useCasePart.basicFlow() .step(SYSTEM_DISPLAYS_TEXT).system(displaysConstantText()); Collection<Step> steps = useCasePart.getUseCase().getSteps(); assertEquals(1, steps.size()); Optional<FlowStep> previousStep = ((FlowStep) steps.iterator().next()).getPreviousStepInFlow(); assertFalse(previousStep.isPresent()); }
@Test public void continuesWithoutAlternativeAtFirstStepCalledFromFirstStepOfAlternativeFlowWithoutEvent() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_TEXT_AGAIN).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_NUMBER).user(EntersNumber.class).system(displaysEnteredNumber()) .flow(ALTERNATIVE_FLOW).insteadOf(CUSTOMER_ENTERS_TEXT) .step(CONTINUE).continuesWithoutAlternativeAt(CUSTOMER_ENTERS_TEXT) .build(); modelRunner.run(model).reactTo(entersText(), entersText()); assertRecordedStepNames(CONTINUE, CUSTOMER_ENTERS_TEXT, CUSTOMER_ENTERS_TEXT_AGAIN); }
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) .step("S6").system(this::stops) .flow("Handle out-of-bounds age").insteadOf("S5").condition(this::ageIsOutOfBounds) .step("S5a_1").system(this::informsUserAboutOutOfBoundsAge) .step("S5a_2").continuesAt("S3") .flow("Handle non-numerical age").insteadOf("S5") .step("S5b_1").on(NON_NUMERICAL_AGE).system(this::informsUserAboutNonNumericalAge) .step("S5b_2").continuesAt("S3") .build(); return model; }
modelBuilder .useCase("Included use case") .basicFlow() .step("Included step").system(promptsUserToEnterName()) .useCase("Get greeted") .basicFlow() .step("S1").system(promptsUserToEnterName()) .step("S2").user(entersName()).system(greetsUser()) .step("S4a_1").system(blowsUp()) .step("S4a_2").continuesAt("S1") .flow("Alternative flow B").after("S3") .step("S4b_1").continuesAfter("S2") .flow("Alternative flow C").condition(thereIsNoAlternative()) .step("S5a").continuesWithoutAlternativeAt("S4") .flow("Alternative flow D").insteadOf("S4").condition(thereIsNoAlternative()) .step("S4c_1").includesUseCase("Included use case") .step("S4c_2").continuesAt("S1") .flow("EX").anytime() .step("EX1").on(Exception.class).system(logsException()) .build();
/** * Creates a handler for events or exceptions of the specified type. * <p> * Internally, a default use case ("Handles events") is created in the model. * </p> * * @param eventOrExceptionClass the specified event / exception class * @param <T> the type of events/exceptions * @return a part of the builder used to create the event handler (the "system reaction") */ public <T> FlowlessUserPart<T> on(Class<T> eventOrExceptionClass) { FlowlessUserPart<T> on = useCase(HANDLES_EVENTS).on(eventOrExceptionClass); return on; }
@Test public void createsSingleStepThatHandlesUserCommandWithUseCaseButWithoutFlow() { UseCasePart useCasePart = modelBuilder.useCase(USE_CASE); Model model = useCasePart .on(EntersText.class).system(displaysEnteredText()) .build(); UseCase useCase = useCasePart.getUseCase(); Collection<Step> steps = useCase.getSteps(); assertEquals(1, steps.size()); Step step = steps.iterator().next(); assertEquals("S1", step.getName()); assertEquals(USE_CASE, step.getUseCase().getName()); assertEquals(model.getSystemActor(), step.getActors()[0]); }
public <T> FlowlessUserPart<T> on(Class<T> eventOrExceptionClass) { ConditionPart conditionPart = condition(null); FlowlessUserPart<T> flowlessUserPart = conditionPart.on(eventOrExceptionClass); return flowlessUserPart; }
FlowPart(Flow flow, UseCasePart useCasePart) { this.flow = flow; this.useCasePart = useCasePart; this.useCase = useCasePart.getUseCase(); }
@Test public void continuesAfterSecondStepCalledFromFirstStepOfAlternativeFlowWithoutEvent() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_TEXT_AGAIN).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_NUMBER).user(EntersNumber.class).system(displaysEnteredNumber()) .flow(ALTERNATIVE_FLOW).insteadOf(CUSTOMER_ENTERS_TEXT_AGAIN) .step(CONTINUE).continuesAfter(CUSTOMER_ENTERS_TEXT_AGAIN) .build(); modelRunner.run(model).reactTo(entersText(), entersNumber()); assertRecordedStepNames(CUSTOMER_ENTERS_TEXT, CONTINUE, CUSTOMER_ENTERS_NUMBER); }
@Test public void createsTwoStepsAndCheckIfTheyExistInUseCaseByName() { UseCasePart useCasePart = modelBuilder.useCase(USE_CASE); useCasePart.basicFlow() .step(SYSTEM_DISPLAYS_TEXT).system(displaysConstantText()) .step(SYSTEM_DISPLAYS_TEXT_AGAIN).system(displaysConstantText()); Collection<Step> steps = useCasePart.getUseCase().getSteps(); assertEquals(2, steps.size()); boolean firstUseCaseStepExists = useCasePart.getUseCase().hasStep(SYSTEM_DISPLAYS_TEXT); boolean secondUseCaseStepExists = useCasePart.getUseCase().hasStep(SYSTEM_DISPLAYS_TEXT_AGAIN); assertTrue(firstUseCaseStepExists); assertTrue(secondUseCaseStepExists); }
public Model buildWith(ModelBuilder modelBuilder) { normalUser = modelBuilder.actor("Normal User"); anonymousUser = modelBuilder.actor("Anonymous User"); Model model = modelBuilder.useCase("Get greeted") .basicFlow() .step("S1").as(normalUser).system(this::promptsUserToEnterFirstName) .step("S2").as(normalUser).user(ENTERS_FIRST_NAME).system(this::savesFirstName) .step("S3").as(normalUser, anonymousUser).system(this::promptsUserToEnterAge) .step("S4").as(normalUser, anonymousUser).user(ENTERS_AGE).system(this::savesAge) .step("S5").as(normalUser).system(this::greetsUserWithFirstName) .step("S6").as(normalUser, anonymousUser).system(this::greetsUserWithAge) .step("S7").as(normalUser, anonymousUser).system(this::stops) .flow("Handle out-of-bounds age").insteadOf("S5").condition(this::ageIsOutOfBounds) .step("S5a_1").system(this::informsUserAboutOutOfBoundsAge) .step("S5a_2").continuesAt("S3") .flow("Handle non-numerical age").insteadOf("S5") .step("S5b_1").on(NON_NUMERICAL_AGE).system(this::informsUserAboutNonNumericalAge) .step("S5b_2").continuesAt("S3") .flow("Anonymous greeted with age only").insteadOf("S5").condition(this::ageIsOk) .step("S5c_1").as(anonymousUser).continuesAt("S6") .flow("Anonymous does not enter name").insteadOf("S1") .step("S1a_1").as(anonymousUser).continuesAt("S3") .build(); return model; }
@Test public void twoFlowlessStepsReactWhenConditionIsTrueInSecondStepWithoutEvent() { Model model = modelBuilder.useCase(USE_CASE) .on(EntersText.class).system(displaysEnteredText()) .condition(() -> modelRunner.getLatestStep().isPresent() && modelRunner.getLatestStep().get().getEventClass().equals(EntersText.class)).system(displaysConstantText()) .build(); modelRunner.run(model).reactTo(entersText()); assertEquals(ModelRunner.class, modelRunner.getLatestStep().get().getEventClass()); }
@Test public void createsTwoStepsWithoutFlow() { UseCasePart useCasePart = modelBuilder.useCase(USE_CASE); useCasePart .on(EntersText.class).system(displaysEnteredText()) .on(EntersNumber.class).system(displaysEnteredNumber()) .build(); Collection<Step> steps = useCasePart.getUseCase().getSteps(); assertEquals(2, steps.size()); Iterator<Step> stepIt = steps.iterator(); Step step = stepIt.next(); assertEquals("S1", step.getName()); assertEquals(USE_CASE, step.getUseCase().getName()); step = stepIt.next(); assertEquals("S2", step.getName()); assertEquals(USE_CASE, step.getUseCase().getName()); }
/** * Only if the specified condition is true, the event is handled. * * @param condition * the condition that constrains when the event is handled * @return a part of the builder used to define the event's class */ public ConditionPart condition(Condition condition) { return useCase(HANDLES_EVENTS).condition(condition); }
/** * Start the "happy day scenario" where all is fine and dandy. * * @return the flow part to create the steps of the basic flow. */ public FlowPart basicFlow() { Flow useCaseFlow = getUseCase().getBasicFlow(); return new FlowPart(useCaseFlow, this); }
public Model buildWith(ModelBuilder modelBuilder) { Model model = modelBuilder.useCase("Get greeted") .basicFlow() .step("S1").system(this::greetsUser) .step("S2").system(this::printsHooray).reactWhile(this::lessThanThreeHooraysHaveBeenPrinted) .build(); return model; }
@Test public void continuesAtThirdStepCalledFromFirstStepOfAlternativeFlowWithoutEvent() { Model model = modelBuilder .useCase(USE_CASE) .basicFlow() .step(CUSTOMER_ENTERS_TEXT).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_TEXT_AGAIN).user(EntersText.class).system(displaysEnteredText()) .step(CUSTOMER_ENTERS_NUMBER).user(EntersNumber.class).system(displaysEnteredNumber()) .flow(ALTERNATIVE_FLOW).insteadOf(CUSTOMER_ENTERS_TEXT_AGAIN) .step(CONTINUE).continuesAt(CUSTOMER_ENTERS_NUMBER) .build(); modelRunner.run(model).reactTo(entersText(), entersNumber()); assertRecordedStepNames(CUSTOMER_ENTERS_TEXT, CONTINUE, CUSTOMER_ENTERS_NUMBER); }