当前位置: 首页 > 知识库问答 >
问题:

Java——如何单元测试TimSort和“一般契约违反”问题

杜海
2023-03-14

这个问题与“比较方法违反了它的一般契约!”——TimSort和GdriLayout以及其他几个类似的“违反一般契约”问题有关。我的问题特别与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 可以在区域和/或轨道字段中包含字母字符,并且可以选择具有一个或两个字符的字母后缀。有效刻度是 [0000, 9999] 范围内的所有整数(即使表示为 String)。所有有效的 Tick 编号都是有效的 GIS 刻度编号,但有效的 GIS 刻度也可能看起来像 A912、R123、0123G、A346*

我的对称性违规是,在GisTick<code>compareTo</code>中,我考虑了可能的后缀,但在纯Tick<code>compareTo</code>中,我没有考虑它。因此,如果“this”是0000Gis Tick,而“that”是0000*Gis Ticket,则0000.compareTo(0000*)将返回0。而如果“thise”是0000*0000Tick,则0000*。compareTo(0000)将返回1。明显的对称违规(一旦护罩拉回)

根据Ceekay在对链接问题的回答中的说法,

    < li >创建包含32个或更多对象的列表。 < li >在该列表中,需要运行两次或更多次。 < li >每次运行必须包含3个或更多对象。

一旦您满足这三个标准,您就可以开始测试此故障。

我相信我已经为我的单元测试设置了这样一个TickNumber(和GisTickNumber)对象列表,但我似乎不会让测试失败。尽管列表中有100多个对象,但有两个以上的运行,每个运行包含大约10个对象。因此,我的问题是,为了调用<code>Collections,测试对象列表还需要满足哪些特性。排序(testList)是否因“常规(对称)合同违反”而失败?

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

共有1个答案

尚声
2023-03-14

已解决:
我最终调试到一个断点,在该断点中我可以查看正在排序的列表中对象的 toString() 表示形式,然后能够从该数据的其余部分中提取 TickNumber 信息,并最终在我的单元测试中使用该提取的数据。最后,我返回并删除了列表项,直到我制作了一个似乎满足触发对称相关“一般合同违规”的“最低要求”的列表。

我不确定如何将我的特定解决方案概括为列表必须满足的通用特征,以触发 TimsSort 和这种“一般合同违规”。但是在这里...

  • 列表必须包含64个元素(49 1 12 1 1)
  • 列表必须包含50的运行,其中50个元素中的49个比较结果为0(即比较匹配)
    • 在匹配运行的前半部分,必须有一个元素在运行中的所有其他元素之前排序(运行中的所有其他元素在比较时匹配),并且该单个奇数元素也必须在其他运行结束时“对称不匹配”该元素。
    • “对称性不匹配”的另一半必须是4次运行(另一次运行)中的最后一项

    我很确定上面的要点并不是列表在排序时暴露对称破坏所必须满足的全部要求,但是它们在一个特定的情况下对我有效。

    具体来说,我精心制作的测试列表从49个TickNumber对象开始,其中Tick = "9999 ",在49个Tick的前半部分有一个" 9910" Tick,在这个开放的伪运行中总共有50个Tick数字。(伪,因为“9910”打破了49个匹配“9999”记号的未排序运行。)开始运行中的“9910”记号是我测试的对称不匹配的一半。那么测试列表包含12个GisTickNumber对象,作为8的运行(“9915*”、“9920*”、“9922*”、“9931*”、“9933*”、“9934*”、“9936*”、“9939*”),接着是4的运行(“9907*”、“9908*”、“9909*”、“9910*”)。请注意,4的最后一项是我正在测试的“对称不匹配”的另一半。最后,列表以一个“9901”tick number对象结束,该对象将开始排序列表,还有一个“9978 *”gistick number对象,该对象在中间某处排序。我已经尝试删除和/或重新排列测试列表中的对象,但没有效果。例如,如果从测试列表中删除了“9901”元素,单元测试将开始发布假阳性(成功)结果。(如果将“9901”移动到未排序列表的前面,也会出现误报)

    注意:我怀疑“9910”对称失配的纯TickNumber部分可能出现在MIN_run元素之前的开场运行中的任何位置。换句话说,如果MIN_RUN是32,并且我的测试列表中的前一个运行有50个元素,其中49个元素比较“相同”,那么“9910”对称失配元素可以出现在运行中小于位置32的任何位置。这个假设尚未被证明;但我根据经验确定,对称失配元素不可能出现在领先运行的末尾附近,并且它可能出现在接近领先运行开始的多个位置。(每次测试运行一个不同的点)

    一般来说,如果这些条件中的任何一个不是“完全正确的”,那么即使您正在测试列表数据,比较应该违反合同,您也不会触发“一般合同违反”。

    就我而言,在我的测试列表中匹配的唯一 TickNumber 对象是 49 个“9999”时钟周期和 2 个(“9910”和“9910*”)时钟周期,它们在比较时违反了对称性。

 类似资料:
  • 我知道它已经被询问和回答了数百万次,但我仍然无法弄清楚为什么我在排序期间收到了违规。这是我的代码: 我收到了这个错误 有什么想法吗?

  • 我有时会得到一个 for 我可以始终如一地抛出此异常,实时数据运行足够长的时间,但我不确定如何解决问题的实际原因。 我的比较仪有什么问题?(具体来说,我违反了合同的哪一部分?)如何在不掩盖异常的情况下修复它? 我使用的是 Java 7,如果不进行重大重写就无法升级。 我可以通过将设置为来掩盖异常,但这不是一个理想的解决方案。 我尝试创建测试来随机生成数据并验证每个合同条件。我无法抛出异常。 我尝试

  • 我制作了一个带有jPanel和JLabel数组的调色板。起初它运行良好,但后来我从 JPanel 中取出了一些其他 jLabels,并添加了一些事件。现在我不断收到此错误: 我试图删除第一次收到此错误后所做的一切,但仍然不断收到它。当我将布局从 GridLayout 更改为其他任何内容时,错误消失了,但代码变得无用。所以我需要网格布局。当我将该 JPanel 中的所有内容移动到另一个 JPanel

  • FuelPHP 以自动测试的想法建成,并且基于 PHPUnit 测试框架来包含测试和测试类别。 单元测试是什幺? 单元测试是被写来确保程式码单元(通常是一个函式或方法)是否有执行它原设计行为的自动测试。 这些测试也帮助开发者确保他们对系统所作的任何变更,不会破坏原有运作中的任何东西。 单元测试也是测试驱动开发(TDD)学问的关键原动力。 PHPUnit 你将需要本地安装的 PHPUnit,如果你想

  • 我在整理名单 排序代码: FinalSentence类标头: compareTo()实现: 这是例外: 对于一个小列表(少于 50 个元素),它可以工作。对于一个大型列表(它也应该与那些一起使用),它会引发此异常。列表的实例类型是 ArrayList,这并不重要。 我不知道如何深入了解这一点。列表已满,元素类型相同(那里没有多态性),但是对于大型列表,我得到了这个奇怪的例外。 有什么想法吗? 谢谢

  • 问题内容: 我看到了很多与此有关的问题,并试图解决该问题,但是经过一个小时的搜索和大量的试验和错误后,我仍然无法修复它。我希望你们中的一些人能抓住问题。 这是我得到的: 这是我的比较器: 任何想法? 问题答案: 异常消息实际上是描述性的。这里所指的合同是传递:如果和那么对于任意的。我用纸和铅笔检查了一下,你的代码似乎有几个孔: 如果你不返回。 如果id不相等,则返回。你应该返回-1或1根据哪个ID