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
相关产品推荐
相关产品推荐

