Я написал сопоставители типов с использованием Mapstruct для выполнения некоторых общих задач при отображении между сущностями и DTO, таких как переименование свойств, «выбор вишен» их путем перемещения их из вложенной структуры до уровня root и т.д. c. Начальная реализация Po C выглядит следующим образом:
@Mapper(
componentModel = "spring",
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
uses = {DocumentationMapper.class},
imports = {Kind.class})
public interface ConnectorMapper {
@Mapping(source = "metadata.extendedProperties", target = "metadata.additionalProperties")
@Mapping(source = "metadata.documentation", target = "documentation")
@Mapping(source = "metadata.name", target = "name")
@Mapping(source = "spec", target = "connectorSpecYaml")
ConnectorDto fromEntity(final ConnectorYaml connectorYaml);
@InheritInverseConfiguration
@Mapping(target = "kind", expression = "java(Kind.Connector)")
ConnectorYaml fromDto(final ConnectorDto connectorDto);
}
Этот преобразователь в основном выполняет следующие действия:
- Переименовывает вложенное свойство
metadata.extendedProperties
в metadata.additionalProperties
и наоборот. наоборот. - Cherry - выбрать вложенное свойство
metadata.documentation
для DTO и применить правила отображения, определенные в DocumentationMapper
(с помощью предложения uses
), и наоборот. - Cherry- выберите вложенное свойство
metadata.name
для DTO и наоборот. - Переименуйте свойство
spec
в connectorSpecYaml
и наоборот.
Для модульного тестирования При таком поведении мне пришлось написать несколько сумасшедших утверждений, которые больше не читаются:
@Test
public void connectorMapperFromEntity() {
// GIVEN a connector entity with fixed values
final var connector = FixtureBuilder.createConnectorYaml("connector");
// WHEN mapping the entity to a DTO
final var connectorDto = connectorMapper.fromEntity(connector);
// THEN the mapping yields a result
assertThat(connectorDto).isNotNull();
// AND the name has been cherry-picked from metadata into the target
assertThat(connectorDto.getName()).isEqualTo(connector.getMetadata().getName());
// AND the metadata has been mapped correctly
assertThat(connectorDto.getMetadata())
.isEqualToIgnoringGivenFields(connector.getMetadata(), "additionalProperties");
// AND the extended properties in metadata have been renamed correctly
assertThat(connectorDto.getMetadata().getAdditionalProperties())
.isEqualTo(connector.getMetadata().getExtendedProperties());
// AND the documentation has been cherry-picked into the target
assertThat(connectorDto.getDocumentation())
.isEqualToIgnoringGivenFields(
connector.getMetadata().getDocumentation(), "additionalProperties");
// AND the extended properties in documentation have been renamed correctly
assertThat(connectorDto.getDocumentation().getAdditionalProperties())
.isEqualTo(connector.getMetadata().getDocumentation().getExtendedProperties());
// AND the spec has been mapped correctly
assertThat(connectorDto.getConnectorSpecYaml()).isEqualTo(connector.getSpec());
}
Другое направление одинаково грубо для чтения из-за ручной сборки DTO из данных прибора:
@Test
public void connectorMapperFromDto() {
final var fixture = FixtureBuilder.createConnectorYaml("connector");
final var connectorDto =
ConnectorDto.builder()
.connectorSpecYaml(fixture.getSpec())
.metadata(
MetadataDto.builder()
.additionalProperties(fixture.getMetadata().getExtendedProperties())
.labels(fixture.getMetadata().getLabels())
.build())
.documentation(
DocumentationDto.builder()
.additionalProperties(
fixture.getMetadata().getDocumentation().getExtendedProperties())
.exampleUsage(fixture.getMetadata().getDocumentation().getExampleUsage())
.longDescription(fixture.getMetadata().getDocumentation().getLongDescription())
.shortDescription(
fixture.getMetadata().getDocumentation().getShortDescription())
.exampleResponse(fixture.getMetadata().getDocumentation().getExampleResponse())
.build())
.name(fixture.getMetadata().getName())
.build();
final var connector = connectorMapper.fromDto(connectorDto);
assertThat(connector).isNotNull();
assertThat(connector).isEqualTo(fixture);
}
В этот момент мне было любопытно, существуют ли другие подходы для упрощения тестирования картографов, которые не выполняют простых операций переименования. Я думал о некотором способе жестко кодировать входные и ожидаемые выходные объекты в JSON, а не создавать и сравнивать их вручную. Это осуществимый подход или есть что-то более подходящее?