首页 > 解决方案 > 具有相同输出的 ArrayList 上的 AssertionError

问题描述

我知道这个话题已经被问过很多次了,我搜索了所有可能的解决方案,但不幸的是没有解决我的问题。

这是我的测试用例:

@Test
    public void whenFindAllBy_thenReturnListofViewPlanDetailDto() {
        java.sql.Date startDate = new java.sql.Date(new Date().getTime());
        java.sql.Date endDate = new java.sql.Date(new Date().getTime());
        Plan planA = new Plan();
        planA.setName("Plan A - 2018");
        entityManager.persist(planA);
        entityManager.flush();
        Module moduleA = new Module();
        moduleA.setName("CSS");
        moduleA.setDescription("CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript.");
        entityManager.persist(moduleA);

        Module moduleB = new Module();
        moduleB.setName("HTML");
        moduleB.setDescription("Hypertext Markup Language is the standard markup language for creating web pages and web applications.");
        entityManager.persist(moduleB);

        PlanDetail planDetailA = new PlanDetail();
        planDetailA.setInstructor("Mozilla Firefox Foundation");
        planDetailA.setStartDate(startDate);
        planDetailA.setEndDate(endDate);
        planDetailA.setModule(moduleA);
        planDetailA.setPlan(planA);
        entityManager.persist(planDetailA);


        PlanDetail planDetailB = new PlanDetail();
        planDetailB.setInstructor("W3 Schools");
        planDetailB.setStartDate(startDate);
        planDetailB.setEndDate(endDate);
        planDetailB.setModule(moduleB);
        planDetailB.setPlan(planA);
        entityManager.persist(planDetailB);

        entityManager.flush();

        List<ViewPlanDetailDto> plandetails = new ArrayList<>();
        plandetails.add(new ViewPlanDetailDto(planDetailA.getId(), planDetailA.getModule().getName(), planDetailA.getModule().getDescription(), planDetailA.getInstructor(), planDetailA.getStartDate(), planDetailA.getEndDate()));
        plandetails.add(new ViewPlanDetailDto(planDetailB.getId(), planDetailB.getModule().getName(), planDetailB.getModule().getDescription(), planDetailB.getInstructor(), planDetailB.getStartDate(), planDetailB.getEndDate()));

        assertEquals(planRepository.findAllBy(planA.getId()), plandetails);

    }

堆栈跟踪:

java.lang.AssertionError: expected: java.util.ArrayList<[ViewPlanDetailDto(detailId=1, name=CSS, description=CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript., instructor=Mozilla Firefox Foundation, startDate=2018-07-06, endDate=2018-07-06), ViewPlanDetailDto(detailId=2, name=HTML, description=Hypertext Markup Language is the standard markup language for creating web pages and web applications., instructor=W3 Schools, startDate=2018-07-06, endDate=2018-07-06)]> but was: java.util.ArrayList<[ViewPlanDetailDto(detailId=1, name=CSS, description=CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript., instructor=Mozilla Firefox Foundation, startDate=2018-07-06, endDate=2018-07-06), ViewPlanDetailDto(detailId=2, name=HTML, description=Hypertext Markup Language is the standard markup language for creating web pages and web applications., instructor=W3 Schools, startDate=2018-07-06, endDate=2018-07-06)]>

我尝试的是:覆盖 PlanDetail、ViewPlanDetailDto、Plan 上的等于,但这一切都失败了。

等于和哈希码覆盖:

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof ViewPlanDetailDto))
            return false;
        ViewPlanDetailDto other = (ViewPlanDetailDto) obj;
        if (description == null) {
            if (other.description != null)
                return false;
        } else if (!description.equals(other.description))
            return false;
        if (detailId == null) {
            if (other.detailId != null)
                return false;
        } else if (!detailId.equals(other.detailId))
            return false;
        if (endDate == null) {
            if (other.endDate != null)
                return false;
        } else if (!endDate.equals(other.endDate))
            return false;
        if (instructor == null) {
            if (other.instructor != null)
                return false;
        } else if (!instructor.equals(other.instructor))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (startDate == null) {
            if (other.startDate != null)
                return false;
        } else if (!startDate.equals(other.startDate))
            return false;
        return true;
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((description == null) ? 0 : description.hashCode());
        result = prime * result + ((detailId == null) ? 0 : detailId.hashCode());
        result = prime * result + ((endDate == null) ? 0 : endDate.hashCode());
        result = prime * result + ((instructor == null) ? 0 : instructor.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + ((startDate == null) ? 0 : startDate.hashCode());
        return result;
    }

当我尝试断言它时,即使输出相同,它也总是失败。

基于 IntelliJ 的比较失败,它在预期部分的尾随空格上突出显示,我不知道它是如何结束尾随空格的。

区别

标签: springunit-testingspring-data-jpa

解决方案


equals()您可能会错误地覆盖。
要理解和纠正您的问题,您应该从基础开始:对您的equals()方法进行单元测试(顺便考虑覆盖hashCode()以与equals()合同保持一致)。

无论如何,equals()通过指定类的所有实例字段来覆盖以在单元测试中执行某些断言通常是您可以避免的,并且如果它给equals().
equals()有一个语义定义在Object.equals()

指示其他对象是否“等于”这个对象。

你应该坚持这一点。
通常,我使用诸如 Harmcrest 或 AssertJ 之类的单元测试匹配器库以非侵入性的方式对对象的字段执行断言,同时简单明了。

使用 AssertJ,您的断言可能如下所示:

Assertions.assertThat(planRepository.findAllBy(planA.getId()))
          // assert result size
          .hasSize(2) 
          // extract a field to assert
          .extracting(ViewPlanDetailDto::getPlanDetail) 
          // extract still finer fields to assert
          .extracting(PlanDetail::getId, p -> p.getModule().getName(), p -> p.getModule().geDescription(), ... other fields to assert)
          // declare values expected
          .containsExactly(Tuple.tuple(planDetailA.getId(), "CSS", "CSS is a cornerstone technology of the World Wide Web, alongside HTML and JavaScript.",
                                       planDetailB.getId(), "HTML", "Hypertext Markup Language is the standard markup language for creating web pages and web applications.",
                                       ... other expected tuples ));

推荐阅读