繁体   English   中英

排序列表上的AssertEquals始终返回false

[英]AssertEquals on sorted lists always returning false

我正在尝试编写一个单元测试来测试两个列表的排序。 我所拥有的是调用自定义排序比较器,然后将原始列表与排序后的列表进行比较。 然后,我使用assertEquals来测试排序后的列表和原始列表是否匹配。

假设我有一个简单的模型...患者。

患者有两个字段...名称和年龄。

List<Patient> unOrdered = new ArrayList<Patient>();
List<Patient> ordered = new ArrayList<Patient>();

我用相同的三名病人填补了这两个病人,并正确订购了一个。

ordered.add(new Patient("Chris Bacon", "45"));
ordered.add(new Patient("Charles Steak", "82"));
ordered.add(new Patient("Matt Pork", "32"));

然后,我填写了订购的商品,然后按年龄增长的顺序订购。

unOrdered.add(new Patient("Matt Pork", "32"));
unOrdered.add(new Patient("Chris Bacon", "45"));
unOrdered.add(new Patient("Charles Steak", "82"));

因此,在单元测试中,我编写了一个带有自定义比较器的Collections.sort,以按年龄升序对未排序列表进行排序。 我在测试过程中(对我来说)将该列表打印到控制台,然后执行...

assertEquals(ordered, unOrdered);

控制台以相同的顺序打印出这些列表,但是assertEquals返回false。 我什至尝试以相同的顺序创建两个完全相同的列表,并尝试使用assertEquals,但它仍然返回false。

我不是Java专家,但从网上阅读的书中知道,而且assertEquals文档不仅检查列表中对象的相等性,还检查对象的顺序。 那么...为什么总是返回false? 是assertEquals无法处理更复杂的对象,还是我做错了什么?

为了使两个列表相等,一个列表中的每个元素必须与另一个列表中的相应元素进行比较,因此此测试完全取决于Patient equals方法的实现。

请查看此演示代码,它可以正常运行。 将其与您的相比较并找到问题。

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.junit.Test;

class Patient {
    private String name;
    private String age;

    /**
     * Constructor
     * @param name
     * @param age
     */
    public Patient(String name, String age) {
        super();
        this.name = name;
        this.age = age;
    }

    /**
     * This is the override of super method.
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((age == null) ? 0 : age.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }


    /**
     * This is the override of super method.
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Patient other = (Patient) obj;
        if (age == null) {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }


    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the age
     */
    public String getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(String age) {
        this.age = age;
    }

}

/**
 * Unit test for simple App.
 */
public class AppTest {

    /**
     * Rigourous Test :-)
     */
    @Test
    public void testApp() {
        List<Patient> unOrdered = new ArrayList<Patient>();
        List<Patient> ordered = new ArrayList<Patient>();

        ordered.add(new Patient("Charles Steak", "82"));
        ordered.add(new Patient("Chris Bacon", "45"));
        ordered.add(new Patient("Matt Pork", "32"));

        unOrdered.add(new Patient("Matt Pork", "32"));
        unOrdered.add(new Patient("Chris Bacon", "45"));
        unOrdered.add(new Patient("Charles Steak", "82"));

        Collections.sort(unOrdered, new Comparator<Patient>(){

            /**
             * This method is just for demo. Not well defined.
             *
             * @param o1
             * @param o2
             * @return
             */
            @Override
            public int compare(Patient o1, Patient o2) {
                return o1.getName().compareTo(o2.getName());
            }});

        assertEquals(ordered, unOrdered);
    }
}

比较列表时,基本上取决于List的实现方式。 但是,对于大多数列表,您只需迭代所有元素,然后使用equals方法将元素一一比较。 因此,在您的情况下,您需要为Patient类提供一个equals方法。 而且,像往常一样,还提供了hashCode实现(这被认为是最佳实践)。

这样的事情(如果您使用的是Java 8):

public class Patient {
    private final String age;
    private final String name;

    public Patient(final String name, final String age) {
        this.name = name;
        this.age = age;
    }

    public String getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof Patient) {
            Patient other = (Patient) o;
            return Objects.equals(getName(), other.getName()) && Objects.equals(getAge(), other.getAge());
        }
        return false;
    }

    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge());
    }
}

从侧面讲,此后,我不建议使用String作为age 考虑对年龄"2""10"排序。 字符串值"10"位于"2"之前,这可能不是故意的。

此外,要对Patient对象进行排序,可以使用一些漂亮的Java 8功能,如下所示:

// An unordered list of all patients
List<Patient> allPatients = Arrays.asList(
        new Patient("Matt Pork", "32"),
        new Patient("Chris Bacon", "45"),
        new Patient("Charles Steak", "82")
);

// Sort by name
List<Patient> sortedByName = allPatients.stream()
        .sorted(Comparator.comparing(Patient::getName))
        .collect(Collectors.toList());

// Sort by age
List<Patient> sortedByAge = allPatients.stream()
        .sorted(Comparator.comparing(Patient::getAge))
        .collect(Collectors.toList());

请注意,您实际上并未对基础List排序,而只是创建具有正确顺序的新List

您可以在这个出色的教程中了解有关Java 8 Streams的更多信息, 该教程涵盖了排序,过滤等。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM