Java 简化和改进数据类型映射器的单元测试
我已经使用Mapstruct编写了类型映射程序,用于在实体和DTO之间映射时完成一些常见任务,例如重命名属性,通过将属性从嵌套结构中移到根级别等来“挑选”属性。初始PoC实现如下所示:Java 简化和改进数据类型映射器的单元测试,java,unit-testing,fixtures,mapstruct,Java,Unit Testing,Fixtures,Mapstruct,我已经使用Mapstruct编写了类型映射程序,用于在实体和DTO之间映射时完成一些常见任务,例如重命名属性,通过将属性从嵌套结构中移到根级别等来“挑选”属性。初始PoC实现如下所示: @Mapper( componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR, uses = {DocumentationMapper.class}, imports = {Kind.cl
@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
,反之亦然元数据.documentation
属性,并应用DocumentationMapper
中定义的映射规则(通过uses
子句),反之亦然元数据.name
属性,反之亦然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硬编码输入和预期输出对象,而不是手动构建和比较它们。这是一种可行的方法还是有更合适的方法?您可以用随机测试数据填充DTO。检查如何执行此操作 然后您可以编写这样的测试用例(这有点伪代码,但希望它能传达我的想法):
@试验
公共无效testNonNullCases(){
ConnectorDto controlDto=generateTestData(ConnectorDto.class);
//来来往往
ConnectorYaml结果能力=connectorMapper.fromDto(controlDto);
ConnectorTo ResultTo=connectorMapper.fromEntity(resultEntity);
//使用assertj验证它们(嵌套和全部)
资产(ResultTo)
.使用递归比较()
.ignoringFields(/*要手动执行以覆盖异常的字段)*/
.isEqualTo(controlDto);
//执行其余的断言。
}
@试验
公共无效测试用例(){
//如果在图中省略属性(null)和一些嵌套类,我会添加一个测试用例。只是为了查看是否正确处理了null用例。您可以在生成的代码上使用jacoco(或其他覆盖率)来驱动此测试
}
公共静态T generateTestData(类clz){
//从中获得灵感https://github.com/Blastman/DtoTester/pull/1
}
}
我最终将包含快照的JSON文件存储在resources文件夹中,在测试执行期间加载这些文件,并使用Jackson进行反序列化