You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JUnit 5下含30属性Java对象映射器单元测试优化方案

不拆分测试用例完成30个属性的映射器测试方案

针对SonarLint单个测试用例断言不超过25个的限制,同时不想拆分测试用例,可以用以下几种方案解决:

方案1:嵌套assertAll分组断言

JUnit 5的assertAll支持嵌套结构,把30个断言按业务逻辑分成多个小组,SonarLint会将每个嵌套的assertAll视为单个逻辑断言,不会统计内部的单个断言数量。

修改后的代码示例:

@Test
void devraitConvertireEnApercu() {
    // 创建包含所有字段的documentConventionOTD
    ApercuConvention ressource = mappeur.p2r(documentConventionOTD);

    assertAll("映射器转换全量断言",
            () -> assertNotNull(ressource),
            // 基本信息组
            () -> assertAll("基本信息映射验证",
                    () -> assertEquals(documentConventionOTD.getIdConvention(), ressource.getId()),
                    () -> assertEquals(documentConventionOTD.getTypeConvention(), ressource.getTypeConvention()),
                    () -> assertEquals(documentConventionOTD.getCodeGeo(), ressource.getCodeGeo()),
                    () -> assertEquals(documentConventionOTD.getOrganismeFormation(), ressource.getOrganismeFormation()),
                    () -> assertEquals(documentConventionOTD.getIntituleFormation(), ressource.getIntituleFormation()),
                    () -> assertEquals(documentConventionOTD.getCodePostalLieuFormation(), ressource.getCodePostal()),
                    () -> assertEquals(documentConventionOTD.getVilleLieuFormation(), ressource.getVille())
            ),
            // 日期与金额数量组
            () -> assertAll("日期与金额数量映射验证",
                    () -> assertEquals(documentConventionOTD.getDateDebutConvention(), ressource.getDateDebut()),
                    () -> assertEquals(documentConventionOTD.getNbPlaces(), ressource.getNbPlaces()),
                    () -> assertEquals(documentConventionOTD.getMontantBDCInitial(), ressource.getMontantBDCInitial()),
                    () -> assertEquals(documentConventionOTD.getDateBDCInitial(), ressource.getDateBDCInitial()),
                    () -> assertEquals(documentConventionOTD.getMontantBDCRectificatif(), ressource.getMontantBDCRectificatif()),
                    () -> assertEquals(documentConventionOTD.getDateBDCRectificatif(), ressource.getDateBDCRectificatif())
            ),
            // 预付款相关组
            () -> assertAll("预付款相关映射验证",
                    () -> assertEquals(documentConventionOTD.getMontantTotalAvance(), ressource.getMontantTotalAvance()),
                    () -> assertEquals(documentConventionOTD.getEstAvanceDemandee(), ressource.getEstAvanceDemandee()),
                    () -> assertEquals(documentConventionOTD.getDateCalculAvance(), ressource.getDateCalculAvance()),
                    () -> assertEquals(documentConventionOTD.getEstBeneficiaireAvanceActif(), ressource.getEstBeneficiaireAvanceActif())
            ),
            // 提醒与状态组
            () -> assertAll("提醒与状态映射验证",
                    () -> assertEquals(documentConventionOTD.getEtatRapprochement(), ressource.getEtatRapprochement()),
                    () -> assertEquals(documentConventionOTD.getDateAlerteBDCGenere(), ressource.getDateAlerteBDCGenere()),
                    () -> assertEquals(documentConventionOTD.getEstTraiteeAlerteBDCGenere(), ressource.getEstTraiteeAlerteBDCGenere()),
                    () -> assertEquals(documentConventionOTD.getDateAlerteBDCNonGenere(), ressource.getDateAlerteBDCNonGenere()),
                    () -> assertEquals(documentConventionOTD.getEstTraiteeAlerteBDCNonGenere(), ressource.getEstTraiteeAlerteBDCNonGenere()),
                    () -> assertEquals(documentConventionOTD.getDateAlertePrixTotal(), ressource.getDateAlertePrixTotal()),
                    () -> assertEquals(documentConventionOTD.getEstTraiteeAlertePrixTotal(), ressource.getEstTraiteeAlertePrixTotal())
            ),
            // 剩余属性组
            () -> assertAll("剩余属性映射验证",
                    () -> assertEquals(documentConventionOTD.getDateAlerteNombrePlaceAchetees(), ressource.getDateAlerteNombrePlaceAchetees()),
                    () -> assertEquals(documentConventionOTD.getEstTraiteeAlerteNombrePlaceAchetees(), ressource.getEstTraiteeAlerteNombrePlaceAchetees()),
                    () -> assertEquals(documentConventionOTD.getNumeroBonReservation(), ressource.getNumeroBonReservation()),
                    () -> assertEquals(documentConventionOTD.getCodeTypeSession(), ressource.getTypeSession())
            )
    );
}

方案2:封装自定义断言方法

把相关属性的断言逻辑封装到单独的私有方法中,每个方法内部包含多个断言,但SonarLint只会将方法调用视为单个断言,从而减少计数。

示例代码:

@Test
void devraitConvertireEnApercu() {
    // 创建包含所有字段的documentConventionOTD
    ApercuConvention ressource = mappeur.p2r(documentConventionOTD);

    assertAll(
            () -> assertNotNull(ressource),
            () -> assertBasicInfo(documentConventionOTD, ressource),
            () -> assertDateAndAmount(documentConventionOTD, ressource),
            () -> assertAdvancePaymentInfo(documentConventionOTD, ressource),
            () -> assertAlertAndStatus(documentConventionOTD, ressource),
            () -> assertRemainingFields(documentConventionOTD, ressource)
    );
}

private void assertBasicInfo(DocumentConventionOTD source, ApercuConvention target) {
    assertEquals(source.getIdConvention(), target.getId());
    assertEquals(source.getTypeConvention(), target.getTypeConvention());
    assertEquals(source.getCodeGeo(), target.getCodeGeo());
    assertEquals(source.getOrganismeFormation(), target.getOrganismeFormation());
    assertEquals(source.getIntituleFormation(), target.getIntituleFormation());
    assertEquals(source.getCodePostalLieuFormation(), target.getCodePostal());
    assertEquals(source.getVilleLieuFormation(), target.getVille());
}

private void assertDateAndAmount(DocumentConventionOTD source, ApercuConvention target) {
    assertEquals(source.getDateDebutConvention(), target.getDateDebut());
    assertEquals(source.getNbPlaces(), target.getNbPlaces());
    assertEquals(source.getMontantBDCInitial(), target.getMontantBDCInitial());
    assertEquals(source.getDateBDCInitial(), target.getDateBDCInitial());
    assertEquals(source.getMontantBDCRectificatif(), target.getMontantBDCRectificatif());
    assertEquals(source.getDateBDCRectificatif(), target.getDateBDCRectificatif());
}

private void assertAdvancePaymentInfo(DocumentConventionOTD source, ApercuConvention target) {
    assertEquals(source.getMontantTotalAvance(), target.getMontantTotalAvance());
    assertEquals(source.getEstAvanceDemandee(), target.getEstAvanceDemandee());
    assertEquals(source.getDateCalculAvance(), target.getDateCalculAvance());
    assertEquals(source.getEstBeneficiaireAvanceActif(), target.getEstBeneficiaireAvanceActif());
}

private void assertAlertAndStatus(DocumentConventionOTD source, ApercuConvention target) {
    assertEquals(source.getEtatRapprochement(), target.getEtatRapprochement());
    assertEquals(source.getDateAlerteBDCGenere(), target.getDateAlerteBDCGenere());
    assertEquals(source.getEstTraiteeAlerteBDCGenere(), target.getEstTraiteeAlerteBDCGenere());
    assertEquals(source.getDateAlerteBDCNonGenere(), target.getDateAlerteBDCNonGenere());
    assertEquals(source.getEstTraiteeAlerteBDCNonGenere(), target.getEstTraiteeAlerteBDCNonGenere());
    assertEquals(source.getDateAlertePrixTotal(), target.getDateAlertePrixTotal());
    assertEquals(source.getEstTraiteeAlertePrixTotal(), target.getEstTraiteeAlertePrixTotal());
}

private void assertRemainingFields(DocumentConventionOTD source, ApercuConvention target) {
    assertEquals(source.getDateAlerteNombrePlaceAchetees(), target.getDateAlerteNombrePlaceAchetees());
    assertEquals(source.getEstTraiteeAlerteNombrePlaceAchetees(), target.getEstTraiteeAlerteNombrePlaceAchetees());
    assertEquals(source.getNumeroBonReservation(), target.getNumeroBonReservation());
    assertEquals(source.getCodeTypeSession(), target.getTypeSession());
}

方案3:使用对象递归比较工具(推荐)

用AssertJ的递归比较功能,一个断言就能验证所有属性的映射关系,彻底解决断言数量问题。

先确保项目引入AssertJ依赖,然后修改代码:

import static org.assertj.core.api.Assertions.assertThat;

@Test
void devraitConvertireEnApercu() {
    // 创建包含所有字段的documentConventionOTD
    ApercuConvention ressource = mappeur.p2r(documentConventionOTD);

    assertThat(ressource)
            .isNotNull()
            .usingRecursiveComparison()
            // 针对属性名不一致的字段,手动指定映射关系
            .withEqualsForFields(source -> source.getCodePostalLieuFormation(), "codePostal")
            .withEqualsForFields(source -> source.getVilleLieuFormation(), "ville")
            .isEqualTo(documentConventionOTD);
}

如果两个对象的属性名完全一一对应,甚至可以省略字段映射的配置,直接用usingRecursiveComparison().isEqualTo()完成全量验证。

内容的提问来源于stack exchange,提问作者Samuel Holmes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 04:50:23