Java - 如何对TimSort进行单元测试以及"一般合同违规"问题

时间:2015-12-18 02:10:04

标签: java unit-testing timsort

此问题与"Comparison method violates its general contract!" - TimSort and GridLayout有关  和其他几个类似的违反合同#34;的问题。我的问题与Ceekay在页面底部的答案有关,关于"如何测试TimSort实现"。在我的情况下,我修复了由于对称性违规而导致我在这里的应用程序错误,但是我在创建单元测试以暴露该违规时遇到了问题(如果修复程序在以后被注释掉或未修复)。

public class TickNumber implements Comparable<TickNumber> {
    protected String zone;
    protected String track;
}
public class GisTickNumber extends TickNumber implements Comparable<TickNumber> {
    private String suffix;
}

我遗漏了所有的实施细节,但基本上Tick号码是一个4位数字,前两位数字是区域,后两位数字是轨道。 GisTickNumbers可以在区域和/或跟踪字段中包含字母字符,并且它们可以选择具有一个或两个字符的alpha后缀。有效刻度是[0000, 9999]范围内的所有整数(即使表示为字符串)。所有有效的Tick号码都是有效的Gis Tick号码,但有效的Gis Ticks也可能看起来像A912, R123, 0123G, A346*

我的对称性违规是在GisTick compareTo中,我考虑了可能的后缀,但在普通Tick compareTo中,我没有考虑到它。因此,如果&#39;这个&#39;是一个0000刻度线&#39;&#39;是一个0000* Gis Tick,0000.compareTo(0000*)将返回0.而如果&#39;这个&#39;是一个0000* Gis Tick,&#39;&#39;是一个0000 Tick,0000*.compareTo(0000)将返回1.明显的对称违规(一旦裹尸布撤回)

根据Ceekay对相关问题的回答,

  
      
  1. 创建包含32个或更多对象的列表。
  2.   
  3. 在该列表中,需要[两次或多次]。
  4.   
  5. 每次运行必须包含3个或更多对象。
  6.         

    一旦达到这三个标准,就可以开始测试这个失败。

我相信我已经为我的单元测试设置了一个TickNumber(和GisTickNumber)对象的列表,但我似乎无法让测试失败。即使列表有超过100个对象,也有两个以上的运行,每个运行包含大约10个对象。所以,我的问题是,由于&#34;一般(对称)合同违规&#34;?Collections.sort(testList)失败的其他特征是什么? >

  • 是的,在我运行我预计会失败的单元测试之前,我已经注释掉了修复程序。

1 个答案:

答案 0 :(得分:-1)

解决


我最终调试到断点,在那里我可以查看列表中对象的toString()表示形式,然后能够从其余数据中提取TickNumber信息,并最终在我的数据中使用提取的数据单元测试。最后,我回去并删除了列表项,直到我精心设计了一个满足&#34;最低要求的列表#34;触发与对称相关的违反一般合同的行为&#34;。

我不确定如何将我的特定解决方案概括为列表必须满足的通用特征,以便触发TimsSort以及此违反合同#34;。但是这里......

  • 该列表必须包含64个元素(49 + 1 + 12 + 1 + 1)
  • 该列表必须包含50的运行,其中50个元素中的49个元素的比较结果为0(即比较匹配)
    • 在那个&#34;匹配运行的前半部分&#34;必须有1个元素在运行中的所有其他元素之前排序(运行中的所有其他元素在比较时匹配),并且单个奇数元素也必须&#34;对称性不匹配&#34;另一端的元素运行。
  • 该列表必须包含至少2个其他三个或更多元素的运行(我的测试列表运行8,然后运行4)
    • &#34;对称性不匹配的另一半&#34;必须是4次运行中的最后一项(第二次运行)。
  • 该列表必须包含排序到排序列表开头的(end-1)位置的元素
  • 列表必须包含位于排序列表中间某处的(结束)位置的元素

我非常确定上面的项目符号不是列表必须满足的一般要求的详尽列表,以便在列表排序时暴露对称违规,但在一个特定情况下它们对我有效。

具体来说,我精心设计的测试列表以49个TickNumber对象开始,其中Tick =&#34; 9999&#34;,在49个Ticks的前半部分的某个地方有一个&#34; 9910&#34;勾选,在此开放伪运行中共有50个Tick号码。 (伪原因是&#34; 9910&#34;打破了未匹配的49匹配&#34; 9999&#34; Ticks。)&#34; 9910&#34;开场时的勾选是我正在测试的对称性不匹配的一半。然后测试列表包含12个GisTickNumber对象作为8的运行(&#34; 9915 *&#34;,&#34; 9920 *&#34;,&#34; 9922 *&#34;,&#34 ; 9931 *&#34;,&#34; 9933 *&#34;,&#34; 9934 *&#34;,&#34; 9936 *&#34;,&#34; 9939 *&#34 ;),然后是4(&#34; 9907 *&#34;,&#34; 9908 *&#34;,&#34; 9909 *&#34;,&#34; 9910 *& #34)。注意,4的运行中的最后一项是&#34;对称性不匹配的另一半&#34;我正在测试。最后,该列表将使用&#34; 9901&#34; TickNumber对象将引导排序列表,并且&#34; 9978 *&#34; GisTickNumber对象在中间某处排序。我试过删除和/或重新排列测试列表中的对象无济于事。单元测试将开始发出假阳性(成功)结果,例如,如果&#34; 9901&#34;元素从测试列表中删除。 (如果&#34; 9901&#34;被移动到未排序列表的前面,也会出现误报)

注意:我怀疑&#34; 9910&#34;的普通TickNumber部分。对称性不匹配可以出现在MIN_RUN第3个元素之前的开始运行中的任何位置。换句话说,如果MIN_RUN是32并且我的测试列表中的前导符号有50个元素,其中49个比较&#34;相同的&#34;,那么&#34; 9910&#34;对称性不匹配元素可以出现在小于位置32的运行中的任何位置。这个假设还没有得到证实;但我已经凭经验确定对称性不匹配元素不能出现在领先运行结束附近,并且它可能出现在领先运行开始附近的多个位置。 (每次测试运行一个不同的点)

一般情况下,如果这些条件中的任何一个条件不完全正确,那么#34;你不会触发违反合同的一般行为&#34;即使您正在测试列表数据,其中比较应违反合同。

就我而言,我的测试列表中唯一匹配的TickNumber对象是49&#34; 9999&#34;蜱虫和2(&#34; 9910&#34;和&#34; 9910 *&#34;)蜱虫在比较时违反对称性。