Тестирование операций CRUD с некоторыми особыми случаями с использованием Cucumber

Вопрос

Используя Cucumber и Java17, я провел рефакторинг функциональных тестов для базового приложения CRUD, так как обнаружил, что предыдущие тесты используют специальные переменные для разных тестовых сценариев, и мне показалось, что с ними сложно работать. Итак, я придумал следующее.

Мне говорят, что решение, особенно материал StepLabel, сложное и запутанное. Я согласен, но я не уверен, как упростить это. Мне также говорят, что документы Java шумные и ненужные, и что разделительные блоки в шагах (используемые для организации шагов) также носят ограничительный характер. Одним из требований является обеспечение возможности сопровождения кода инженером по контролю качества.

Что вы думаете об архитектурном подходе, который я выбрал? И как можно упростить компонент StepLabel? И, наконец, согласны ли вы с комментариями, которые я процитировал выше? Спасибо!

Описание архитектуры

Записи приложения CRUD имеют настраиваемый идентификатор записи, некоторые строковые атрибуты и необязательный список. Вот объекты запроса и ответа в тесте:

@Data
public class ContactRequest {
    private String id;
    private String description;
    private String contactInfo;
    private String someField;
    private List<KnownAssociate> knownAssociates = new ArrayList<>();
}

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@SuperBuilder(toBuilder = true)
public class ContactResponse extends BaseResponse {
    private String id;
    private String description;
    private String contactInfo;
    private String someField;
    private List<KnownAssociate> knownAssociates;
    private Instant createdDateTime;
    private Instant updatedDateTime;
}

У нас есть несколько сценариев для тестирования: базовый CRUD (который включает в себя дополнительную конечную точку isExists), создание дублирующего идентификатора и тестирование дополнительной конечной точки listAll.

@contact_app_service_api
Feature: To allow services to perform CRUD operations on the Contact table in the database

  @end_to_end_contact @cleanup_delete_contact
  Scenario Outline: <KnownAssociate> Contact CRUD lifecycle
    When the user creates a contact with known associate <KnownAssociate>
    Then the contact should be created
    When the user retrieves the contact
    Then the contact should be retrieved
    When the user updates the contact
    Then the contact should be updated
    When the user checks if a contact exists
    Then the contact should be shown to exist
    When the user deletes the contact
    Then the contact should be deleted
    When the user checks if a contact exists
    Then the contact should be shown to not exist
      # Delete the contact using after hook tag @cleanup_delete_contact
    Examples:
      | KnownAssociate |
      | None           |
      | TypeOne        |
      | TypeTwo        |
      | TypeThree      |

  @create_invalid_contact @cleanup_delete_contact
  Scenario: Create contact with duplicate contact id fails
    Given a contact exists
    When the user creates a second contact with the same contact id
    Then an error message is returned: "Contact id: <contactId> already exists" and HTTP status 400 after "creation" attempt
      # Delete the contact using after hook tag @cleanup_delete_contact

  @get_all_contact_details
  Scenario: Create, get and delete multiple contacts
    When the user creates 2 contacts
    And the user retrieves all existing contacts
    Then the created 2 contacts exist in the list
    And the 2 contacts should be deleted

Мое намерение состоит в том, чтобы класс определения Step не содержал состояния. Класс Actions будет хранить состояние и обрабатывать вызовы API и оценки утверждений.

public class ContactAppSteps {

    private final ContactAppActions contactAppActions;

    public ContactAppSteps(ContactAppActions contactAppActions) {
        this.contactAppActions = contactAppActions;
    }

    /*
     * NORMAL CRUD OPERATIONS
     */
    @When("the user creates a contact with delivery channel {}")
    public void contactCreation(String knownAssociates) {
        ContactRequest contactRequest;
        if(knownAssociates == null || "none".equalsIgnoreCase(knownAssociates)) {
            contactRequest = contactAppActions.getDefaultContactRequest();
        } else {
            contactRequest = contactAppActions.getDefaultContactRequest(KnownAssociate.valueOf(knownAssociates));
        }
        contactAppActions.createContact(contactRequest);
    }

    @Given("a contact exists")
    public void contactCreation() {
        contactAppActions.createContact();
    }

    @When("the user retrieves the contact")
    public void contactRetrieval() {
        contactAppActions.retrieveContact();
    }

    @When("the user checks if a contact exists")
    public void contactExists() {
        contactAppActions.checkContactExists();
    }

    @When("the user updates the contact")
    public void contactUpdate() {
        contactAppActions.updateContact();
    }

    @When("the user deletes the contact")
    public void contactDeletion() {
        contactAppActions.deleteContact();
    }

    @When("the user retrieves all existing contacts")
    public void allContactRetrieval() {
        contactAppActions.retrieveAllContacts();
    }

    /*
     * SPECIAL OPS
     */
    @When("the user creates a second contact with the same contact id")
    public void createDuplicateContact() {
        String existingContactId = contactAppActions.retrieveContact().getId();
        ContactRequest contactRequest = contactAppActions.getDefaultContactRequest(existingContactId);
        contactAppActions.createContact(contactRequest);
    }

    @When("the user creates {int} contacts")
    public void createMultipleContacts(int contactCount) {
        for(int i = 0; i < contactCount; i++) {
            contactAppActions.createContact(contactAppActions.getDefaultContactRequest());
        }
    }

    @Then("the created {int} contacts exist in the list")
    public void checkIfCreatedContactsExistInList(int contactCount) {
        List<ContactResponse> overallContactResponseList = contactAppActions.fetchContactResponseListFromContext();

        for(int i = 0; i < contactCount; i++) {
            ContactResponse contactResponse = contactAppActions.fetchContactResponseFromContext(new StepLabel(CREATION_RESPONSE, i));
            assertThat(overallContactResponseList).contains(contactResponse);
        }
    }

    @Then("the {int} contacts should be deleted")
    public void deleteContacts(int contactCount) {
        for(int i = 0; i < contactCount; i++) {
            ContactResponse contactResponse = contactAppActions.fetchContactResponseFromContext(new StepLabel(CREATION_RESPONSE, i));
            contactAppActions.deleteContact(contactResponse.getId());
        }
    }

    /*
     * EVALUATIONS
     */
    @Then("the contact should be created")
    public void contactShouldBeCreated() {
        contactAppActions.evaluateCreation();
    }

    @Then("the contact should be retrieved")
    public void contactShouldBeRetrieved() {
        contactAppActions.evaluateRetrieval();
    }

    @Then("the contact should be shown to exist")
    public void contactShouldExist() {
        contactAppActions.evaluateCheckExists(true);
    }

    @Then("the contact should be shown to not exist")
    public void contactShouldNotExist() {
        contactAppActions.evaluateCheckExists(false);
    }

    @Then("the contact should be updated")
    public void contactShouldBeUpdated() {
        contactAppActions.evaluateUpdate();
    }

    @Then("the contact should be deleted")
    public void contactShouldBeDeleted() {
        contactAppActions.evaluateDeletion();
    }

    @Then("all existing contacts should be retrieved")
    public void allContactsShouldBeRetrieved() {
        contactAppActions.evaluateRetrieval();
    }

    @Then("an error message is returned: {string} and HTTP status {int} after {string} attempt")
    public void errorMessageReturned(String message, int status, String operation) {
        if("creation".equalsIgnoreCase(operation)) {
            StepLabel creationStepLabel = new StepLabel(CREATION_RESPONSE);
            if(message.contains("<contactId>")) {
                String contactId = contactAppActions.fetchContactResponseFromContext(creationStepLabel).getId();
                message = message.replace("<contactId>", contactId);
            }
            contactAppActions.evaluateErrorResponse(creationStepLabel.inc(), status, message);
        } else {
            throw new UnsupportedOperationException();
        }
    }

    /*
     * CLEANUP
     */
    @After("@cleanup_delete_contact")
    public void afterDeleteContact() {
        contactAppActions.deleteAllCreatedContacts();
    }
}
public class ContactAppActions {

    public static final String CREATION_RESPONSE = "CREATION_RESPONSE";
    public static final String RETRIEVAL_RESPONSE = "RETRIEVAL_RESPONSE";
    public static final String CHECK_EXISTS_RESPONSE = "CHECK_EXISTS_RESPONSE";
    public static final String UPDATE_RESPONSE = "UPDATE_RESPONSE";
    public static final String DELETION_RESPONSE = "DELETION_RESPONSE";

    private final StepLabelCounter stepLabelCounter = new StepLabelCounter();

    private final ContactAppServiceClient contactAppServiceClient;
    private final ContactAppContext contactAppContext;

    public ContactAppActions(ContactAppServiceClient contactAppServiceClient,
                                   ContactAppContext contactAppContext) {
        this.contactAppServiceClient = contactAppServiceClient;
        this.contactAppContext = contactAppContext;
    }

    /**
     * Creates a ContactRequest with randomly generated data and a generated contact id but with no delivery channel
     */
    public ContactRequest getDefaultContactRequest() {
        return ContactFixtures.generateDefaultContact();
    }

    /**
     * Creates a ContactRequest with randomly generated data and a generated contact id
     */
    public ContactRequest getDefaultContactRequest(KnownAssociate knownAssociate) {
        return ContactFixtures.generateDefaultContact(knownAssociate);
    }

    /**
     * Creates a ContactRequest with randomly generated data but with no delivery channel
     */
    public ContactRequest getDefaultContactRequest(String contactId) {
        return ContactFixtures.generateDefaultContact(contactId);
    }

    /**
     * Creates a ContactRequest with randomly generated data
     */
    public ContactRequest getDefaultContactRequest(String contactId, KnownAssociate knownAssociate) {
        return ContactFixtures.generateDefaultContact(contactId, knownAssociate);
    }

    /**
     * Creates a ContactRequest with the given params. The `knownAssociateEntrys` is optional and is a CSV string
     */
    public ContactRequest getParameterisedContactRequest(Map<String, String> params) {
        return ContactFixtures.generateContactWithParams(params);
    }

    /**
     * Create a contact using randomly generated data
     * @return the created contact
     */
    public ContactResponse createContact() {
        return createContact(getDefaultContactRequest());
    }

    /**
     * Create a contact using the provided request
     * @return the created contact
     */
    public ContactResponse createContact(ContactRequest contactRequest) {
        contactAppContext.setContactRequest(contactRequest);

        Response response = contactAppServiceClient.createContact(contactRequest);
        contactAppContext.getResponseMap().put(stepLabelCounter.getNext(CREATION_RESPONSE), response);
        return contactAppServiceClient.extractContactResponse(response);
    }

    /**
     * Retrieve the contact using the last creation response's contact id
     * @return the retrieved contact
     */
    public ContactResponse retrieveContact() {
        return retrieveContact(extract(contactAppContext.getResponseMap().get(stepLabelCounter.getLatest(CREATION_RESPONSE))).getId());
    }

    /**
     * Retrieve the contact using the provided contact id
     * @return the retrieved contact
     */
    public ContactResponse retrieveContact(String contactId) {
        Response response = contactAppServiceClient.getContact(contactId);
        contactAppContext.getResponseMap().put(stepLabelCounter.getNext(RETRIEVAL_RESPONSE), response);
        return contactAppServiceClient.extractContactResponse(response);
    }

    /**
     * Check if the contact exists, using the last creation response's contact id
     * @return empty response
     */
    public Response checkContactExists() {
        return checkContactExists(extract(contactAppContext.getResponseMap().get(stepLabelCounter.getLatest(CREATION_RESPONSE))).getId());
    }

    /**
     * Check if the contact exists, using the provided contact id
     * @return empty response
     */
    public Response checkContactExists(String contactId) {
        Response response = contactAppServiceClient.existsContact(contactId);
        contactAppContext.getResponseMap().put(stepLabelCounter.getNext(CHECK_EXISTS_RESPONSE), response);
        return response;
    }

    /**
     * Create an update contact request using the last creation response's contact id and randomly generated data
     * @return the updated contact
     */
    public ContactResponse updateContact() {
        String contactId = extract(contactAppContext.getResponseMap().get(stepLabelCounter.getLatest(CREATION_RESPONSE))).getId();
        return updateContact(contactId);
    }

    /**
     * Create an update contact request using the provided contact id and randomly generated data
     * @return the updated contact
     */
    public ContactResponse updateContact(String contactId) {
        ContactRequest contactUpdateRequest = getDefaultContactRequest(contactId);
        return updateContact(contactUpdateRequest);
    }

    /**
     * Create an update contact request using the provided request
     * @return the updated contact
     */
    public ContactResponse updateContact(ContactRequest contactUpdateRequest) {
        contactAppContext.setContactRequest(contactUpdateRequest);

        Response response = contactAppServiceClient.updateContact(contactUpdateRequest.getId(), contactUpdateRequest);
        contactAppContext.getResponseMap().put(stepLabelCounter.getNext(UPDATE_RESPONSE), response);
        return contactAppServiceClient.extractContactResponse(response);
    }

    /**
     * Delete the contact using the last creation response's contact id
     * @return empty response
     */
    public Response deleteContact() {
        String contactId = extract(contactAppContext.getResponseMap().get(stepLabelCounter.getLatest(CREATION_RESPONSE))).getId();
        return deleteContact(contactId);
    }

    /**
     * Delete the contact using the provided contact id
     * @return empty response
     */
    public Response deleteContact(String contactId) {
        Response response = contactAppServiceClient.deleteContact(contactId);
        contactAppContext.getResponseMap().put(stepLabelCounter.getNext(DELETION_RESPONSE), response);
        return response;
    }

    /**
     * Retrieves all contacts
     * @return list of all existing contacts
     */
    public List<ContactResponse> retrieveAllContacts() {
        List<ContactResponse> contactResponseList = contactAppServiceClient.getAllContacts();
        contactAppContext.setContactResponseList(contactResponseList);
        return contactResponseList;
    }

    /**
     * Evaluate creation response against creation request
     */
    public void evaluateCreation() {
        evaluateCreation(stepLabelCounter.getLatest(CREATION_RESPONSE));
    }

    /**
     * Evaluate equality of fields between provided step label's response and creation request
     */
    public void evaluateCreation(StepLabel stepLabelForActualResponse) {
        Response response = contactAppContext.getResponseMap().get(stepLabelForActualResponse);
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_CREATED);
        evaluateEquality(response);
    }

    /**
     * Evaluate equality of fields between last retrieval response and last creation response
     */
    public void evaluateRetrieval() {
        evaluateRetrieval(stepLabelCounter.getLatest(RETRIEVAL_RESPONSE), stepLabelCounter.getLatest(CREATION_RESPONSE));
    }

    /**
     * Evaluate equality of fields between provided step label's response and another provided step label's response.
     * This method is provided for flexibility for non-standard flows
     */
    public void evaluateRetrieval(StepLabel stepLabelForActualResponse, StepLabel stepLabelForExpectedResponse) {
        Response actualResponse = contactAppContext.getResponseMap().get(stepLabelForActualResponse);
        Response expectedResponse = contactAppContext.getResponseMap().get(stepLabelForExpectedResponse);
        evaluateRetrieval(actualResponse, expectedResponse);
    }

    /**
     * Evaluate equality of fields between provided response and another provided response.
     * This method is provided for flexibility for non-standard flows and where context is not used
     */
    public void evaluateRetrieval(Response actualResponse, Response expectedResponse) {
        assertThat(actualResponse.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
        evaluateEquality(actualResponse, expectedResponse);
    }

    /**
     * Evaluate status of last existence check response
     * @param exists check if response status shows contact exists (HTTP 200) or if doesn't exist (HTTP 404)
     */
    public void evaluateCheckExists(boolean exists) {
        Response response = contactAppContext.getResponseMap().get(stepLabelCounter.getLatest(CHECK_EXISTS_RESPONSE));
        evaluateCheckExists(response, exists);
    }

    /**
     * Evaluate status of provided existence check response
     * @param exists check if response status shows contact exists (HTTP 200) or if doesn't exist (HTTP 404)
     */
    public void evaluateCheckExists(Response response, boolean exists) {
        if(exists) {
            assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_OK);
        } else {
            assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_NOT_FOUND);
        }
    }

    /**
     * Evaluate relevant equality and difference of fields between update response and update request,
     * and update response and creation response, respectively
     */
    public void evaluateUpdate() {
        evaluateUpdate(stepLabelCounter.getLatest(UPDATE_RESPONSE), stepLabelCounter.getLatest(CREATION_RESPONSE));
    }

    /**
     * Evaluate relevant equality and difference of fields between provided step label's response and latest generated
     * contact request (this would be the update request if updateContact(_) was called), and provided step label's
     * response and another provided step label's response, respectively
     */
    public void evaluateUpdate(StepLabel stepLabelForActualResponse, StepLabel stepLabelForExpectedResponse) {
        Response actualResponse = contactAppContext.getResponseMap().get(stepLabelForActualResponse);
        Response expectedResponse = contactAppContext.getResponseMap().get(stepLabelForExpectedResponse);
        ContactRequest updateContactRequest = contactAppContext.getContactRequest();
        evaluateUpdate(actualResponse, expectedResponse, updateContactRequest);
    }

    /**
     * Evaluate relevant equality and difference of fields between provided response and update request,
     * and provided response and another provided response, respectively
     */
    public void evaluateUpdate(Response actualResponse, Response expectedResponse, ContactRequest updateContactRequest) {
        assertThat(actualResponse.getStatusCode()).isEqualTo(HttpStatus.SC_OK);

        evaluateDifference(extract(actualResponse), extract(expectedResponse));
        evaluateEquality(extract(actualResponse), updateContactRequest);
    }

    /**
     * Evaluate success of deletion of last delete response
     */
    public void evaluateDeletion() {
        Response response = contactAppContext.getResponseMap().get(stepLabelCounter.getLatest(DELETION_RESPONSE));
        evaluateDeletion(response);
    }

    /**
     * Evaluate success of deletion of provided response
     */
    public void evaluateDeletion(Response response) {
        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SC_NO_CONTENT);
    }

    /**
     * Evaluate error fields of provided response
     */
    public void evaluateErrorResponse(StepLabel stepLabelForResponse, int expectedHttpStatus, String expectedErrorMessage) {
        evaluateErrorResponse(contactAppContext.getResponseMap().get(stepLabelForResponse), expectedHttpStatus, expectedErrorMessage);
    }

    /**
     * Evaluate error fields of provided response
     */
    public void evaluateErrorResponse(Response response, int expectedHttpStatus, String expectedErrorMessage) {
        assertThat(response.getStatusCode()).isEqualTo(expectedHttpStatus);
        assertThat(extractError(response).getError().getMessage()).isEqualTo(expectedErrorMessage);
    }

    /**
     * Evaluate equality of fields between the provided step label's response and latest generated contact request
     */
    public void evaluateEquality(StepLabel stepLabelForActualResponse) {
        evaluateEquality(extract(contactAppContext.getResponseMap().get(stepLabelForActualResponse)), contactAppContext.getContactRequest());
    }

    /**
     * Evaluate equality of fields between the provided response and latest generated contact request
     */
    public void evaluateEquality(Response actualResponse) {
        evaluateEquality(extract(actualResponse), contactAppContext.getContactRequest());
    }

    /**
     * Evaluate equality of fields between the provided contact response and request
     * This method is provided for flexibility for non-standard flows and where context is not used
     */
    public void evaluateEquality(ContactResponse actualContactResponse, ContactRequest expectedContactRequest) {
        evaluateContactFieldsEquality(actualContactResponse, expectedContactRequest.getId(), expectedContactRequest.getDescription(), expectedContactRequest.getContactInfo(), expectedContactRequest.getSomeField(), expectedContactRequest.getKnownAssociateEntrys());
    }

    /**
     * Evaluate equality of fields between the two provided responses
     * This method is provided for flexibility for non-standard flows and where context is not used
     */
    public void evaluateEquality(Response actualResponse, Response expectedResponse) {
        evaluateEquality(extract(actualResponse), extract(expectedResponse));
    }

    /**
     * Evaluate equality of fields between the two provided step label's responses
     * This method is provided for flexibility for non-standard flows
     */
    public void evaluateEquality(StepLabel stepLabelForActualResponse, StepLabel stepLabelForExpectedResponse) {
        evaluateEquality(extract(contactAppContext.getResponseMap().get(stepLabelForActualResponse)), extract(contactAppContext.getResponseMap().get(stepLabelForExpectedResponse)));
    }

    /**
     * Evaluate equality of fields between the provided response and the step label's response
     * This method is provided for flexibility for non-standard flows
     */
    public void evaluateEquality(Response actualContactResponse, StepLabel stepLabelForExpectedResponse) {
        evaluateEquality(extract(actualContactResponse), extract(contactAppContext.getResponseMap().get(stepLabelForExpectedResponse)));
    }

    /**
     * Evaluate equality of fields between the two provided contact responses
     * This method is provided for flexibility for non-standard flows and where context is not used
     */
    public void evaluateEquality(ContactResponse actualContactResponse, ContactResponse expectedContactResponse) {
        evaluateContactFieldsEquality(actualContactResponse, expectedContactResponse.getId(), expectedContactResponse.getDescription(), expectedContactResponse.getContactInfo(), expectedContactResponse.getSomeField(), expectedContactResponse.getKnownAssociateEntrys());
    }

    private void evaluateContactFieldsEquality(ContactResponse actualContactResponse, String contactId, String description, String contactInfo, String someField, List<KnownAssociateEntry> knownAssociateEntrys) {
        assertThat(actualContactResponse.getId()).isEqualTo(contactId);
        assertThat(actualContactResponse.getDescription()).isEqualTo(description);
        assertThat(actualContactResponse.getContactInfo()).isEqualTo(contactInfo);
        assertThat(actualContactResponse.getSomeField()).isEqualTo(someField);
        if(actualContactResponse.getKnownAssociateEntrys() == null || actualContactResponse.getKnownAssociateEntrys().isEmpty()) {
            assertThat(knownAssociateEntrys == null || knownAssociateEntrys.isEmpty()).isTrue();
        } else {
            assertThat(actualContactResponse.getKnownAssociateEntrys()).isEqualTo(knownAssociateEntrys);
        }
    }

    /**
     * Evaluate difference of fields between the two provided contact responses except creation date time
     */
    public void evaluateDifference(ContactResponse actual, ContactResponse expected) {
        assertThat(actual.getDescription()).as("Description should be updated").isNotEqualTo(expected.getDescription());
        assertThat(actual.getContactInfo()).as("ContactInfo should be updated").isNotEqualTo(expected.getContactInfo());
        assertThat(actual.getSomeField()).as("SomeField should be updated").isNotEqualTo(expected.getSomeField());
        assertThat(actual.getUpdatedDateTime()).as("UpdatedDateTime should be updated").isNotEqualTo(expected.getUpdatedDateTime());

        assertThat(actual.getCreatedDateTime()).as("CreatedDateTime should be the same").isEqualTo(expected.getCreatedDateTime());
    }

    /**
     * Extracts a ContactResponse object from a provided response
     * Throws error if no ContactResponse body exists
     */
    public ContactResponse extract(Response response) {
        return contactAppServiceClient.extractContactResponse(response);
    }

    /**
     * Extracts a ErrorResponse object from a provided response
     * Throws error if no ErrorResponse body exists
     */
    public ErrorResponse extractError(Response response) {
        return contactAppServiceClient.extractErrorResponse(response);
    }

    /**
     * Fetch the relevant contact response from the context, given the provided step label
     * This method is provided for flexibility for non-standard flows
     */
    public ContactResponse fetchContactResponseFromContext(StepLabel stepLabel) {
        return extract(contactAppContext.getResponseMap().get(stepLabel));
    }

    /**
     * Fetch the contact response list from the context (populated using the retrieveAllContacts() function)
     * This method is provided for flexibility for non-standard flows
     */
    public List<ContactResponse> fetchContactResponseListFromContext() {
        return contactAppContext.getContactResponseList();
    }

    /**
     * Clean up any contacts referenced in the context as created
     */
    public void deleteAllCreatedContacts() {
        for(int i = 0; i < stepLabelCounter.getLatest(CREATION_RESPONSE).number(); i++) {
            ContactResponse contactResponse = extract(contactAppContext.getResponseMap().get(new StepLabel(CREATION_RESPONSE, i)));
            if(contactResponse.getId() != null) {
                contactAppServiceClient.deleteContact(contactResponse.getId());
            }
        }
    }
}

И, наконец, несколько вспомогательных объектов. StepLabel используется для ссылки на объекты Response для неупорядоченной оценки и предназначен для обеспечения гибкости.

public class StepLabelCounter {
    private final Map<String, Integer> stepCountMap = new HashMap<>();

    public StepLabel getNext(StepLabel stepLabel) {
        return getNext(stepLabel.step());
    }

    /**
     * Increments the step counter and returns the next StepLabel
     * Used for storing a new step's data
     */
    public StepLabel getNext(String step) {
        if(stepCountMap.containsKey(step)) {
            return incAndUpdateAndNext(step, stepCountMap.get(step));
        } else {
            int initialCount = -1;
            return incAndUpdateAndNext(step, initialCount);
        }
    }

    private StepLabel incAndUpdateAndNext(String step, int currentCount) {
        stepCountMap.put(step, currentCount+1);
        return new StepLabel(step, currentCount+1);
    }

    /**
     * Returns the latest StepLabel for the given step
     * Used for referencing the last step's data
     */
    public StepLabel getLatest(String step) {
        return new StepLabel(step, stepCountMap.get(step));
    }
}
public record StepLabel(String step, int number) {
    public StepLabel(String step) {
        this(step, 0);
    }

    public StepLabel inc() {
        return new StepLabel(this.step, number+1);
    }

    public StepLabel withNumber(int number) {
        return new StepLabel(this.step, number);
    }
}
@Data
public class ContactAppContext {

    public ContactAppContext() {
        responseMap = new HashMap<>();
    }

    private ContactRequest contactRequest;

    private Map<StepLabel, Response> responseMap;

    private List<ContactResponse> contactResponseList;
}

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *