簡體   English   中英

用於hashCode / equals契約的JUnit理論

[英]JUnit theory for hashCode/equals contract

以下類用作equals / hashCode契約的通用測試器。 它是本土測試框架的一部分。

  • 你有什么想法?
  • 我怎樣(強)測試這門課程?
  • 這是Junit理論的一個很好的用途?

班級:

@Ignore
@RunWith(Theories.class)
public abstract class ObjectTest {

    // For any non-null reference value x, x.equals(x) should return true
    @Theory
    public void equalsIsReflexive(Object x) {
        assumeThat(x, is(not(equalTo(null))));
        assertThat(x.equals(x), is(true));
    }

    // For any non-null reference values x and y, x.equals(y) 
    // should return true if and only if y.equals(x) returns true.
    @Theory
    public void equalsIsSymmetric(Object x, Object y) {
        assumeThat(x, is(not(equalTo(null))));
        assumeThat(y, is(not(equalTo(null))));
        assumeThat(y.equals(x), is(true));
        assertThat(x.equals(y), is(true));
    }

    // For any non-null reference values x, y, and z, if x.equals(y)
    // returns true and y.equals(z) returns true, then x.equals(z) 
    // should return true.
    @Theory
    public void equalsIsTransitive(Object x, Object y, Object z) {
        assumeThat(x, is(not(equalTo(null))));
        assumeThat(y, is(not(equalTo(null))));
        assumeThat(z, is(not(equalTo(null))));
        assumeThat(x.equals(y) && y.equals(z), is(true));
        assertThat(z.equals(x), is(true));
    }

    // For any non-null reference values x and y, multiple invocations
    // of x.equals(y) consistently return true  or consistently return
    // false, provided no information used in equals comparisons on
    // the objects is modified.
    @Theory
    public void equalsIsConsistent(Object x, Object y) {
        assumeThat(x, is(not(equalTo(null))));
        boolean alwaysTheSame = x.equals(y);

        for (int i = 0; i < 30; i++) {
            assertThat(x.equals(y), is(alwaysTheSame));
        }
    }

    // For any non-null reference value x, x.equals(null) should
    // return false.
    @Theory
    public void equalsReturnFalseOnNull(Object x) {
        assumeThat(x, is(not(equalTo(null))));
        assertThat(x.equals(null), is(false));
    }

    // Whenever it is invoked on the same object more than once 
    // the hashCode() method must consistently return the same 
    // integer.
    @Theory
    public void hashCodeIsSelfConsistent(Object x) {
        assumeThat(x, is(not(equalTo(null))));
        int alwaysTheSame = x.hashCode();

        for (int i = 0; i < 30; i++) {
            assertThat(x.hashCode(), is(alwaysTheSame));
        }
    }

    // If two objects are equal according to the equals(Object) method,
    // then calling the hashCode method on each of the two objects
    // must produce the same integer result.
    @Theory
    public void hashCodeIsConsistentWithEquals(Object x, Object y) {
        assumeThat(x, is(not(equalTo(null))));
        assumeThat(x.equals(y), is(true));
        assertThat(x.hashCode(), is(equalTo(y.hashCode())));
    }

    // Test that x.equals(y) where x and y are the same datapoint 
    // instance works. User must provide datapoints that are not equal.
    @Theory
    public void equalsWorks(Object x, Object y) {
        assumeThat(x, is(not(equalTo(null))));
        assumeThat(x == y, is(true));
        assertThat(x.equals(y), is(true));
    }

    // Test that x.equals(y) where x and y are the same datapoint instance
    // works. User must provide datapoints that are not equal.
    @Theory
    public void notEqualsWorks(Object x, Object y) {
        assumeThat(x, is(not(equalTo(null))));
        assumeThat(x != y, is(true));
        assertThat(x.equals(y), is(false));
    }
}

用法:

import org.junit.experimental.theories.DataPoint;

public class ObjectTestTest extends ObjectTest {

    @DataPoint
    public static String a = "a";
    @DataPoint
    public static String b = "b";
    @DataPoint
    public static String nullString = null;
    @DataPoint
    public static String emptyString = "";
}

需要考慮的一件事是:測試對象與equals合同的一致性應該涉及其他類型的實例。 特別是,子類或超類的實例可能會出現問題。 Joshua Bloch對Effective Java中的相關陷阱給出了很好的解釋(我正在重復使用duffymo的鏈接,因此他應該對此有所了解) - 請參閱涉及Point和ColorPoint類的Transitivity下的部分。

確實,您的實現不會阻止某人編寫涉及子類實例的測試,但由於ObjectTest是一個泛型類,因此它給人的印象是所有數據點都應來自單個類(正在測試的類)。 最好完全刪除類型參數。 只是值得深思。

Joshua Bloch在“Effective Java”的第3章中列出了哈希碼和等號的合同。 看起來你已經涵蓋了很多。 檢查文檔,看看我是否遺漏了任何東西。

也許我錯過了一些東西,但是如果你必須使用具有相同值的DataPoints,則equalsIsSymmetric測試實際上只是正確測試(例如String a =“a”; String a2 =“a”;)否則此測試僅進行當2個參數是一個實例時(即equalsIsSymmetric(a,a);)。 實際上,如果等於遵守“反射”要求而不是對稱要求,則再次測試。

notEqualsWorks(Object x,Object y)理論是錯誤的:根據它們的equals方法,兩個不同的實例在邏輯上可能仍然相等; 你假設實例在邏輯上是不同的,如果它們是不同的引用。

使用上面的示例,下面的兩個不同的數據點(a!= a2)仍然相同,但未通過notEqualsWorks測試:

@DataPoint
public static String a = "a";
@DataPoint
public static String a2 = new String("a");

equalsWorks(Object x, Object y)方法正在執行與equalsIsReflexive(Object x)完全相同的測試。 它應該刪除。

我還認為notEqualsWorks(Object x, Object y)應該被刪除,因為它可以防止人們使用相同的數據點進行其他理論,即使整個測試都是關於擁有這樣的對象。

沒有這樣的數據點,反射性是唯一被測試的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM